Kotlin製ORマッパーのKomapperが5月に1.0のリリースされると聞いてSpringBoot上で試してみました。といってもサンプルソースも豊富なのでそれに毛が生えた程度です。。
H2を利用してperson
テーブルを用意してCRUDを動かします。
create table person
(
id int GENERATED ALWAYS AS IDENTITY (START WITH 3) PRIMARY KEY,
name varchar(255) not null,
email varchar(255) not null
);
テーブルと対になるエンティティとPKなどの項目にアノテーションを定義して項目マッピングを行います。
data class Person(
val id: Int? = null,
val name: String,
val email: String,
)
@KomapperEntityDef(Person::class)
data class PersonDef(
@KomapperId
@KomapperAutoIncrement
val id: Nothing,
)
クエリ実行
QueryDSLを利用してSQLを実行します。メソッドチェーンでやりたいことをつなげていく感じなので直感的でわかりやすいですね。
@Service
class PersonService(
private val database: JdbcDatabase
) {
fun findAll(): List<Person> {
return database.runQuery {
val p = Meta.person
QueryDsl.from(p).orderBy(p.id)
}
}
fun findById(id: Int): Person {
return database.runQuery {
val p = Meta.person
QueryDsl.from(p).where{ p.id eq id }.first()
}
}
@Transactional
fun insert(name: String, email: String): Person {
return database.runQuery {
val person = Person(name = name, email = email)
val p = Meta.person
QueryDsl.insert(p).single(person)
}
}
@Transactional
fun update(id: Int, name: String, email: String): Person {
return database.runQuery {
val person = findById(id)
val p = Meta.person
QueryDsl.update(p).single(person.copy(name = name, email = email))
}
}
@Transactional
fun delete(id: Int) {
database.runQuery {
val person = findById(id)
val p = Meta.person
QueryDsl.delete(p).single(person)
}
}
}
結合
テーブル結合をしたSQLも試してみます。チームテーブル、チームメンバーテーブルを用意して、personテーブルを含めた3テーブルの結合を行います。
DDLは次の通りです。
create table team
(
id int GENERATED ALWAYS AS IDENTITY (START WITH 3) PRIMARY KEY,
name varchar(255) not null
);
create table team_member
(
id int GENERATED ALWAYS AS IDENTITY (START WITH 4) PRIMARY KEY,
team_id int not null,
member_id int not null
);
エンティティとマッピング
data class Team(
val id: Int? = null,
val name: String,
)
@KomapperEntityDef(Team::class)
data class TeamDef(
@KomapperId
@KomapperAutoIncrement
val id: Nothing,
)
data class TeamMember(
val id: Int? = null,
val teamId: Int,
val memberId: Int,
)
@KomapperEntityDef(TeamMember::class)
data class TeamMemberDef(
@KomapperId
@KomapperAutoIncrement
val id: Nothing,
)
left joinを行います。leftJoinメソッドで結合するテーブルを指定し、selectメソッドで取得するカラムを指定します。
@Service
class TeamService(
private val database: JdbcDatabase
) {
fun findById(id: Int): TeamDTO? {
val g = Meta.team
val m = Meta.teamMember
val p = Meta.person
val result = database.runQuery {
QueryDsl.from(g)
.leftJoin(m) { g.id eq m.teamId }
.leftJoin(p) { m.memberId eq p.id }
.where { g.id eq id }
.orderBy(m.id)
.select(g.id, g.name, p.id, p.name, p.email)
}
val members = result.map {
Member(it[p.id]!!, it[p.name]!!, it[p.email]!!)
}
val member = result.first()
val id = member[g.id]
val name = member[g.name]
return TeamDTO(id!!, name!!, members)
}
}
完成したソースは↓です。
github.com
感想
SQLをメソッドチェーンで組み立てていくことができるので悩まずに実装できるのがいいですね。アノテーションプロセッサーを利用しているのでMeta
で指定できるテーブルはコンパイルをしていないと怒られてしまうのは注意が必要です。(大した問題ではないが)
R2DBCに対応しているORマッパーは少ないので採用候補に上がるプロジェクトも多いんじゃないでしょうか。
基本機能を試した程度ですが、これから採用実績は増えていくこと間違いなしだと思います!!