前提
環境は表題の通り以下となります。
- spring boot 2.1.1
- kotlin 1.3.31
- doma 2.24.0
- Intellij
ORマッピングする元のDBは作成されているものとします。
Doma2 + Kotlin
こちらにある通り、「Domaは Kotlin 1.3.11以上を実験的にサポートしています。」とのことなので、自己責任で導入をお願いします。
私が使っている限りでは、いまのところ不具合等は起きていません。
Kotlinで使うと何が良いか?
データをマッピングするEntityクラスを data class として定義できるため色々便利なメソッドが使えたり、NOT NULL なカラムを Entityでは NonNull のプロパティとして定義できたりしてより安全な運用ができます。
特に immutable として Entity を扱う場合はデータの一部を変更してデータをコピーできる copy() メソッドなどは重宝するのではないでしょうか。
私は doma2 の Entity をそのまま使わず 別途定義したクラスにマッピングしているので、単純に java を使わずに実装したかっという気持ちが強いです。
実装
build.gradle
buildscript {
ext {
springBootVersion = '2.1.1.RELEASE'
kotlinVersion = '1.3.31'
mysqlConnectorVersion = '8.0.13'
doma_version = '2.24.0'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
classpath("mysql:mysql-connector-java:$mysqlConnectorVersion")
}
}
apply plugin: 'kotlin-kapt'
kapt {
arguments {
arg("doma.resources.dir", compileKotlin.destinationDir)
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
kapt "org.seasar.doma:doma:$doma_version"
implementation "org.seasar.doma:doma:$doma_version"
implementation group: 'org.seasar.doma.boot', name: 'doma-spring-boot-starter', version: '1.1.1'
implementation group: 'mysql', name: 'mysql-connector-java', version: mysqlConnectorVersion
}
task copyDomaResources(type: Sync) {
from sourceSets.main.resources.srcDirs
into compileKotlin.destinationDir
include 'doma.compile.config'
include 'META-INF/**/*.sql'
include 'META-INF/**/*.script'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
dependsOn copyDomaResources
}
processResources {
filesMatching('**/application.yml') {
filter(
ReplaceTokens,
tokens: [
'datasourceUrl' : "${datasourceUrl}".toString(),
'datasourceUser' : "${datasourceUser}".toString(),
'datasourcePassword': "${datasourcePassword}".toString()
]
)
}
}
doma-spring-boot-starter
- dependenciesに追加します。
- application.ymlに書いた設定をDIしてくれるannotationが使えるようになります。
- Daoで sql ファイルの生成が楽になります。
- 詳細はこちら
apply plugin: 'kotlin-kapt'
- kaptを使います
- 以下も必ず記述
kapt {
arguments {
arg("doma.resources.dir", compileKotlin.destinationDir)
}
}
copyDomaResources
- Domaで使用する sql ファイルをコピーするタスク
- compileKotlinにタスクへの依存関係を記述します。
Intellijの設定
Compilerの Enable annotation processing を有効にする
ビルドをgradleに移譲する
- 教えてくれた人によるとIntellijのビルドはgradleの複雑な文法を理解してくれないらしいので、gradleにビルドを移譲しましょう。
- 移譲しないと copyDomaResources とか走りませんでした。
application.yml
spring:
profiles:
active: local, development
# MySQL接続情報
datasource:
url: @datasourceUrl@
username: @datasourceUser@
password: @datasourcePassword@
hikari:
connection-init-sql: SELECT 1
- DBへの接続情報を記載しています。
- @で括った箇所は適宜読み替えてください。
Entity
@Entity(immutable = true)
@Table(name = "hoge", schema = "test")
data class HogeEntity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
val id: Long? = null,
@Column(name = "name")
val name: String,
@Column(name = "created_at")
val createdAt: LocalDateTime
)
data class
- Entityは data class として定義してください。
@Entity
- Entityであることを示すアノテーション
- immutable = true にします(Entityのプロパティ値が変更不可になります)
@Table
- どの schema のどの table かを指定しています。
- schema は指定がなければ defaultの schema が指定されます。
@Id
- プライマリーキーであることを示します。
@GeneratedValue
- id値を自動的に生成します。
- mysql の場合は
strategy = GenerationType.IDENTITY
を指定すればいいはず。 - DB 側で
AUTO INCREMENT
を指定する必要があります。
@Column
- 対応するカラム名を指定します。
- NOT NULLじゃない場合はプロパティをnullableにしてください。
Dao
@ConfigAutowireable
@Dao
interface HogeEntityDao {
@Select
fun selectById(id: Long): HogeEntity
@Insert
fun insert(entity: HogeEntity): Result<HogeEntity>
@BatchInsert
fun insert(entities: List<HogeEntity>): BatchResult<HogeEntity>
@Update
fun update(entity: HogeEntity): Result<HogeEntity>
@Delete
fun delete(entity: HogeEntity): Result<HogeEntity>
}
@ConfigAutowireable
- application.ymlで指定したdomaの設定をDIします。
@Dao
- Daoであることを示します。
- これを指定することでコンパイル時に実装クラスが自動生成されます。
@Select
- データ取得メソッドに対して付与します。名前のまんまSELECT相当。
- このアノテーションを付与すると、対となるsqlファイルがない場合にエラーになります。
- Intellij で option + Enter すると以下のように生成することが出来ます。
@Update, @Delete, @BatchInsert
- それぞれ、そのままの意味で使用することが出来ます。
-
@BatchInsert(sqlFile = true
にすると@Selectと同じように直接sql文が書けます。
sql
SELECT *
FROM test.hoge
WHERE id = /* id */1;
SELECT *
- 対象のEntityクラスにマッピングします。
- table = entityじゃないときは直接指定でマッピングもできます。こちらを参照→SQL templates — Doma documentation
/* id */1
-
/* */
でくくられたプロパティで後ろの値を置き換えます。 - この場合は
fun selectById(id: Long)
で定義されているパラメータ id の値になります。
まとめ
様々なORMライブラリがありますが、今回はDoma2を使用してみました。
Sql文をそのまま書けることや、やりたいことに対して結構柔軟に記述できる(Daoのfunctionに@Sqlアノテーションで直接sql文を書けたりもする)ので悪くないなと思いました。
難点はKotlinが実験的に対応されていることと、Entityなどの自動生成ツールがないことでしょうか。DBからDaoとEntityを自動生成する domagen というのもあったのですが、こちらは少々癖が強かったりkotlinに対応していなかったので使用をやめました。
ベストなORMライブラリを見つけたい。