Association API

概要

Association APIは、 includeincludeAll を指定したクエリを実行して得られるEntityStoreから関連オブジェクトを簡単に辿れるようにします。 専用のアノテーションをエンティティクラス(もしくはエンティティ定義クラス)に注釈すると 関連オブジェクトの走査のためのユーティリティ関数が生成されます。

アノテーション

@KomapperOneToOne

注釈されたエンティティクラスとターゲットとなるエンティティクラスの間にone-to-oneの関係があることを示します。

@KomapperEntity
@KomapperOneToOne(targetEntity = Address::class)
data class Employee(...)

targetEntityプロパティには関連先のエンティティクラス(もしくはエンティティ定義クラス)を指定します。 指定は必須です。

navigatorプロパティには関連を走査するためのユーティリティ関数の名前を指定します。 指定しない場合、targetEntityプロパティに指定した値から推測されます。

上述の定義からは以下のユーティリティ関数が生成されます。

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

注釈されたエンティティクラスとターゲットとなるエンティティクラスの間にone-to-manyの関係があることを示します。

@KomapperEntity
@KomapperManyToOne(targetEntity = Department::class)
data class Employee(...)

targetEntityプロパティには関連先のエンティティクラス(もしくはエンティティ定義クラス)を指定します。 指定は必須です。

navigatorプロパティには関連を走査するためのユーティリティ関数の名前を指定します。 指定しない場合、targetEntityプロパティに指定した値から推測されます。

上述の定義からは以下のユーティリティ関数が生成されます。

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

注釈されたエンティティクラスとターゲットとなるエンティティクラスの間にmany-to-oneの関係があることを示します。

@KomapperEntity
@KomapperOneToMany(targetEntity = Employee::class, navigator = "employees")
data class Department(...)

targetEntityプロパティには関連先のエンティティクラス(もしくはエンティティ定義クラス)を指定します。 指定は必須です。

navigatorプロパティには関連を走査するためのユーティリティ関数の名前を指定します。 指定しない場合、targetEntityプロパティに指定した値から推測されます。

上述の定義からは以下のユーティリティ関数が生成されます。

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()
}

関連元のエンティティメタモデルと関連先のエンティティメタモデルを示します。 以下のアノテーションのlinkプロパティに指定できます。

  • @KomapperOneToOne
  • @KomapperManyToOne
  • @KomapperOneToMany

@KomapperAggregateRoot

注釈されたエンティティクラスが集約のルートになることを示します。

@KomapperEntity
@KomapperAggregateRoot(navigator = "departments")
data class Department(...)

navigatorプロパティには集約のルートを取り出すためのユーティリティ関数の名前を指定します。 指定しない場合、注釈されたクラスから推測されます。

上述の定義からは以下のユーティリティ関数が生成されます。

fun org.komapper.core.dsl.query.EntityStore.`departments`(
    target: example._Department = org.komapper.core.dsl.Meta.`department`,
    ): Set<example.Department> {
    return this[target]
}

利用例

エンティティクラス定義

次のようなエンティティクラスの定義があるとします。

@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,
)

走査のコード

生成されたユーティリティ関数を使うことで、EntityStoreから関連オブジェクトを簡潔に取り出せます。

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}")
    }
}

context receiverを使った走査のコード

komapper.enableEntityStoreContext オプションを有効にすると、EntityStoreの引数を明示的に渡す必要がなくなるのでより簡潔に関連オブジェクトを走査できます。

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}")
        }
    }
}
最終更新 February 23, 2023: Simplify sample code (99184db)