Version v1.14 of the documentation is no longer actively maintained. The site that you are currently viewing is an archived snapshot. For up-to-date documentation, see the latest version.
Association API
Overview
The Association API makes it easy to navigate association objects from the EntityStore obtained by executing a query specifying include or includeAll.
Annotating an entity class (or entity definition class) with a dedicated annotation generates a utility function for navigating association objects.
Note
The Association API is an experimental feature. To use it, add the following code to your Gradle build script:
tasks {
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions.freeCompilerArgs += listOf("-opt-in=org.komapper.annotation.KomapperExperimentalAssociation")
}
}
Annotations
@KomapperOneToOne
Indicates a one-to-one relationship between the annotated entity class and the target entity class.
@KomapperEntity
@KomapperOneToOne(targetEntity = Address::class)
data class Employee(...)
The targetEntity
property specifies the entity class (or entity definition class) associated with the annotated class.
The specification is required.
The navigator
property specifies the name of a utility function for navigating the association.
If not specified, it is inferred from the value specified for the targetEntity
property.
The following utility function is generated from the above definition:
fun example.Employee.`address`(
store: org.komapper.core.dsl.query.EntityStore,
source: example._Employee = org.komapper.core.dsl.Meta.`employee`,
target: example._Address = org.komapper.core.dsl.Meta.`address`,
): example.Address? {
return store.oneToOne(source, target)[this]
}
@KomapperManyToOne
Indicates a many-to-one relationship between the annotated entity class and the target entity class.
@KomapperEntity
@KomapperManyToOne(targetEntity = Department::class)
data class Employee(...)
The targetEntity
property specifies the entity class (or entity definition class) associated with the annotated class.
The specification is required.
The navigator
property specifies the name of a utility function for navigating the association.
If not specified, it is inferred from the value specified for the targetEntity
property.
The following utility function is generated from the above definition:
fun example.Employee.`department`(
store: org.komapper.core.dsl.query.EntityStore,
source: example._Employee = org.komapper.core.dsl.Meta.`employee`,
target: example._Department = org.komapper.core.dsl.Meta.`department`,
): example.Department? {
return store.manyToOne(source, target)[this]
}
@KomapperOneToMany
Indicates a one-to-many relationship between the annotated entity class and the target entity class.
@KomapperEntity
@KomapperOneToMany(targetEntity = Employee::class, navigator = "employees")
data class Department(...)
The targetEntity
property specifies the entity class (or entity definition class) associated with the annotated class.
The specification is required.
The navigator
property specifies the name of a utility function for navigating the association.
If not specified, it is inferred from the value specified for the targetEntity
property.
The following utility function is generated from the above definition:
fun example.Department.`employees`(
store: org.komapper.core.dsl.query.EntityStore,
source: example._Department = org.komapper.core.dsl.Meta.`department`,
target: example._Employee = org.komapper.core.dsl.Meta.`employee`,
): Set<example.Employee> {
return store.oneToMany(source, target)[this] ?: emptySet()
}
@KomapperLink
Indicates the associated source entity metamodel and the associated target entity metamodel.
It can be specified in the link
property of the following annotations:
@KomapperOneToOne
@KomapperManyToOne
@KomapperOneToMany
@KomapperAggregateRoot
Indicates that the annotated entity class (or entity definition class) is the aggregate root.
@KomapperEntity
@KomapperAggregateRoot(navigator = "departments")
data class Department(...)
The navigator
property specifies the name of a utility function to retrieve the aggregate root.
If not specified, it is inferred from the annotated class.
The above definition generates the following utility function:
fun org.komapper.core.dsl.query.EntityStore.`departments`(
target: example._Department = org.komapper.core.dsl.Meta.`department`,
): Set<example.Department> {
return this[target]
}
Example
Entity class definitions
Suppose we have the following entity class definitions:
@KomapperEntity
@KomapperOneToOne(targetEntity = Employee::class)
data class Address(
@KomapperId
val addressId: Int,
val street: String,
)
@KomapperEntity
@KomapperAggregateRoot("departments")
@KomapperOneToMany(targetEntity = Employee::class, navigator = "employees")
data class Department(
@KomapperId
val departmentId: Int,
val departmentName: String,
)
@KomapperEntity
@KomapperManyToOne(targetEntity = Department::class)
@KomapperOneToOne(targetEntity = Address::class)
data class Employee(
@KomapperId
val employeeId: Int,
val employeeName: String,
val departmentId: Int,
val addressId: Int,
)
Navigation code
We can concisely retrieve the association objects from the EntityStore
by using the generated utility functions:
val a = Meta.address
val e = Meta.employee
val d = Meta.department
val query = QueryDsl.from(a)
.innerJoin(e) {
a.addressId eq e.addressId
}.innerJoin(d) {
e.departmentId eq d.departmentId
}.includeAll()
val store: EntityStore = db.runQuery(query)
for (department in store.departments()) {
val employees = department.employees(store)
for (employee in employees) {
val address = employee.address(store)
println("department=${department.departmentName}, employee=${employee.employeeName}, address=${address?.street}")
}
}
Navigation code using context receiver
Enabling the komapper.enableEntityStoreContext
option allows more concise navigation of association objects
by eliminating the need to pass EntityStore
arguments explicitly.
val a = Meta.address
val e = Meta.employee
val d = Meta.department
val query = QueryDsl.from(a)
.innerJoin(e) {
a.addressId eq e.addressId
}.innerJoin(d) {
e.departmentId eq d.departmentId
}.includeAll()
val store: EntityStore = db.runQuery(query)
with(store.asContext()) {
for (department in departments()) {
val employees = department.employees()
for (employee in employees) {
val address = employee.address()
println("department=${department.departmentName}, employee=${employee.employeeName}, address=${address?.street}")
}
}
}