Files
exposed-wiki/DAO.md
2020-04-08 12:29:24 +03:00

4.5 KiB
Raw Blame History


Overview

The DAO (Data Access Object) API of Exposed, is similar to ORM frameworks like Hibernate with specific Kotlin API.
A DB table is represented by an object inherited from org.jetbrains.exposed.sql.Table like that:

object StarWarsFilms : Table() {
  val id: Column<Int> = integer("id").autoIncrement().primaryKey()
  val sequelId: Column<Int> = integer("sequel_id").uniqueIndex()
  val name: Column<String> = varchar("name", 50)
  val director: Column<String> = varchar("director", 50)
}

Tables that contains Int id with the name id can be declared like that:

object StarWarsFilms : IntIdTable() {
  val sequelId: Column<Int> = integer("sequel_id").uniqueIndex()
  val name: Column<String> = varchar("name", 50)
  val director: Column<String> = varchar("director", 50)
}

Note that these Column types will be defined automatically, so you can also just leave them away. This would produce the same result as the example above:

object StarWarsFilms : IntIdTable() {
  val sequelId = integer("sequel_id").uniqueIndex()
  val name = varchar("name", 50)
  val director = varchar("director", 50)
}

An entity instance or a row in the table is defined as a class instance:

class StarWarsFilm(id: EntityID<Int>) : IntEntity(id) {
 companion object : IntEntityClass<StarWarsFilm>(StarWarsFilms)

 var sequelId by StarWarsFilms.sequelId 
 var name     by StarWarsFilms.name
 var director by StarWarsFilms.director
}

Basic CRUD operations

Create

val movie = StarWarsFilm.new {
  name = "The Last Jedi"
  sequelId = 8
  director = "Rian Johnson"
}

Read

To get entities use one of the following

val movies = StarWarsFilm.all()
val movies = StarWarsFilm.find {StarWarsFilms.sequelId eq 8}
val movie = StarWarsFilm.findById(5)

Read a value from a property similarly to any property in a Kotlin class:

val name = movie.name

Update

Update a value of a property similarly to any property in a Kotlin class:

movie.name = "Episode VIII  The Last Jedi"

Delete

movie.delete() 

Referencing

Simple reference

Let's say you have this table:

object Users: IntIdTable() {
    val name = varchar("name", 50)
}

class User(id: EntityID<Int>): IntEntity(id) {
    companion object : IntEntityClass<User>(Users)

    var name by Users.name
}

And now you want to add a table referencing this table (and other tables!):

object UserRatings: IntIdTable() {
    val value = long("value")
    val film = reference("film", StarWarsFilms)
    val user = reference("user", Users)
}

class UserRating(id: EntityID<Int>): IntEntity(id) {
    companion object : IntEntityClass<UserRating>(UserRatings)

    var value by UserRatings.value
    var film by StarWarsFilm referencedOn UserRatings.film // use referencedOn for normal references
    var user by User referencedOn UserRatings.user
}

Now you can get the film for a rating in the same way you would get any other field:

filmRating.film // returns a StarWarsFilm object

Now if you wanted to get all the ratings for a film, you could do that by using the FilmRating.find function, but what is much easier is to just add a referrersOn field to the StarWarsFilm class:

class StarWarsFilm(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<StarWarsFilm>(StarWarsFilms)

    ...
    val ratings by UserRating referrersOn UserRatings.film // make sure to use val and backReferencedOn
    ...
}

You can call:

movie.ratings // returns all UserRating objects with this movie as film

Optional reference

You can also add an optional reference:

object UserRatings: IntIdTable() {
    ...
    val secondUser = reference("second_user", Users).nullable() // this reference is nullable!
    ...
}

class UserRating(id: EntityID<Int>): IntEntity(id) {
    companion object : IntEntityClass<UserRating>(UserRatings)

    ...
    var secondUser by User optionalReferencedOn UserRatings.secondUser // use optionalReferencedOn for nullable references
    ...
}

Now secondUser will be a nullable field. Of course you can still use referrersOn.