diff --git a/documentation-website/Writerside/topics/Deep-Dive-into-DAO.md b/documentation-website/Writerside/topics/Deep-Dive-into-DAO.md index a88fde6c10..ae35dd3a9d 100644 --- a/documentation-website/Writerside/topics/Deep-Dive-into-DAO.md +++ b/documentation-website/Writerside/topics/Deep-Dive-into-DAO.md @@ -81,33 +81,33 @@ movie.delete() ### many-to-one reference Let's say you have this table: ```kotlin -object Users: IntIdTable() { +object Users : IntIdTable() { val name = varchar("name", 50) } -class User(id: EntityID): IntEntity(id) { +class User(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(Users) var name by Users.name } ``` And now you want to add a table referencing this table (and other tables!): ```kotlin -object UserRatings: IntIdTable() { +object UserRatings : IntIdTable() { val value = long("value") val film = reference("film", StarWarsFilms) val user = reference("user", Users) } -class UserRating(id: EntityID): IntEntity(id) { +class UserRating(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(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: +Now you can get the film for a `UserRating` object, `filmRating`, in the same way you would get any other field: ```kotlin 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: +Now if you wanted to get all the ratings for a film, you could do that by using the `filmRating.find` function, but it is much easier to just add a `referrersOn` field to the `StarWarsFilm` class: ```kotlin class StarWarsFilm(id: EntityID) : IntEntity(id) { companion object : IntEntityClass(StarWarsFilms) @@ -116,10 +116,22 @@ class StarWarsFilm(id: EntityID) : IntEntity(id) { ... } ``` -You can call: +You can then access this field on a `StarWarsFilm` object, `movie`: ```kotlin movie.ratings // returns all UserRating objects with this movie as film ``` +Now imagine a scenario where a user only ever rates a single film. If you want to get the single rating for that user, you can add a `backReferencedOn` field to the `User` class to access the `UserRating` table data: +```kotlin +class User(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(Users) + ... + val rating by UserRating backReferencedOn UserRatings.user // make sure to use val and backReferencedOn +} +``` +You can then access this field on a `User` object, `user1`: +```kotlin +user1.rating // returns a UserRating object +``` ### Optional reference You can also add an optional reference: ```kotlin @@ -135,7 +147,7 @@ class UserRating(id: EntityID): IntEntity(id) { ... } ``` -Now `secondUser` will be a nullable field, and you should use `optionalReferrersOn` instead of `referrersOn` to get all the ratings for a `secondUser`. +Now `secondUser` will be a nullable field, and `optionalReferrersOn` should be used instead of `referrersOn` to get all the ratings for a `secondUser`. ```kotlin class User(id: EntityID): IntEntity(id) { diff --git a/exposed-dao/src/main/kotlin/org/jetbrains/exposed/dao/EntityClass.kt b/exposed-dao/src/main/kotlin/org/jetbrains/exposed/dao/EntityClass.kt index a577fbc0ab..b50c2ac060 100644 --- a/exposed-dao/src/main/kotlin/org/jetbrains/exposed/dao/EntityClass.kt +++ b/exposed-dao/src/main/kotlin/org/jetbrains/exposed/dao/EntityClass.kt @@ -294,46 +294,138 @@ abstract class EntityClass, out T : Entity>( private inline fun registerRefRule(column: Column<*>, ref: () -> R): R = refDefinitions.getOrPut(column to R::class, ref) as R + /** + * Registers a reference as a field of the child entity class, which returns a parent object of this `EntityClass`. + * + * The reference should have been defined by the creation of a [column] using `reference()` on the child table. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTests.Child + */ infix fun > referencedOn(column: Column) = registerRefRule(column) { Reference(column, this) } + /** + * Registers an optional reference as a field of the child entity class, which returns a parent object of + * this `EntityClass`. + * + * The reference should have been defined by the creation of a [column] using either `optReference()` or + * `reference().nullable()` on the child table. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTests.Post + */ infix fun > optionalReferencedOn(column: Column) = registerRefRule(column) { OptionalReference(column, this) } + /** + * Registers a reference as an immutable field of the parent entity class, which returns a child object of + * this `EntityClass`. + * + * The reference should have been defined by the creation of a [column] using `reference()` on the child table. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTestsData.YEntity + */ infix fun , Target : Entity, REF : Comparable> EntityClass.backReferencedOn( column: Column ): ReadOnlyProperty, Target> = registerRefRule(column) { BackReference(column, this) } + /** + * Registers a reference as an immutable field of the parent entity class, which returns a child object of + * this `EntityClass`. + * + * The reference should have been defined by the creation of a [column] using `reference()` on the child table. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTestsData.YEntity + */ @JvmName("backReferencedOnOpt") infix fun , Target : Entity, REF : Comparable> EntityClass.backReferencedOn( column: Column ): ReadOnlyProperty, Target> = registerRefRule(column) { BackReference(column, this) } + /** + * Registers an optional reference as an immutable field of the parent entity class, which returns a child object of + * this `EntityClass`. + * + * The reference should have been defined by the creation of a [column] using either `optReference()` or + * `reference().nullable()` on the child table. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTests.Student + */ infix fun , Target : Entity, REF : Comparable> EntityClass.optionalBackReferencedOn( column: Column ) = registerRefRule(column) { OptionalBackReference, REF>(column as Column, this) } + /** + * Registers an optional reference as an immutable field of the parent entity class, which returns a child object of + * this `EntityClass`. + * + * The reference should have been defined by the creation of a [column] using either `optReference()` or + * `reference().nullable()` on the child table. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTests.Student + */ @JvmName("optionalBackReferencedOnOpt") infix fun , Target : Entity, REF : Comparable> EntityClass.optionalBackReferencedOn( column: Column ) = registerRefRule(column) { OptionalBackReference, REF>(column, this) } + /** + * Registers a reference as an immutable field of the parent entity class, which returns a collection of + * child objects of this `EntityClass` that all reference the parent. + * + * The reference should have been defined by the creation of a [column] using `reference()` on the child table. + * + * By default, this also stores the loaded entities to a cache. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityHookTestData.Country + */ infix fun , Target : Entity, REF : Comparable> EntityClass.referrersOn(column: Column) = registerRefRule(column) { Referrers, TargetID, Target, REF>(column, this, true) } + /** + * Registers a reference as an immutable field of the parent entity class, which returns a collection of + * child objects of this `EntityClass` that all reference the parent. + * + * The reference should have been defined by the creation of a [column] using `reference()` on the child table. + * + * Set [cache] to `true` to also store the loaded entities to a cache. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTests.School + */ fun , Target : Entity, REF : Comparable> EntityClass.referrersOn( column: Column, cache: Boolean ) = registerRefRule(column) { Referrers, TargetID, Target, REF>(column, this, cache) } + /** + * Registers an optional reference as an immutable field of the parent entity class, which returns a collection of + * child objects of this `EntityClass` that all reference the parent. + * + * The reference should have been defined by the creation of a [column] using either `optReference()` or + * reference().nullable()` on the child table. + * + * By default, this also stores the loaded entities to a cache. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTests.Category + */ infix fun , Target : Entity, REF : Comparable> EntityClass.optionalReferrersOn( column: Column ) = registerRefRule(column) { OptionalReferrers, TargetID, Target, REF>(column, this, true) } + /** + * Registers an optional reference as an immutable field of the parent entity class, which returns a collection of + * child objects of this `EntityClass` that all reference the parent. + * + * The reference should have been defined by the creation of a [column] using either `optReference()` or + * `reference().nullable()` on the child table. + * + * Set [cache] to `true` to also store the loaded entities to a cache. + * + * @sample org.jetbrains.exposed.sql.tests.shared.entities.EntityTests.Student + */ fun , Target : Entity, REF : Comparable> EntityClass.optionalReferrersOn( column: Column, cache: Boolean = false