Doma2のinsertで採番されたIDを戻り値で取得したい
きっかけ
Doma2だとinsertの戻り値でシーケンス採番後のエンティティが取得できる。
これがあると何がうれしいかというと、親子関係のエンティティで親のデータを挿入した際のDBで採番されたIDを利用して子のデータを作るみたいなことが簡単にできる。
なんだけれども、なんだか採番されたIDが返ってこなくて困ったので正しい書き方をメモ。
問題のコード
DAOはこんな感じ。
外部ファイルのinsert文を実行するSQL。
この戻り値でDBで採番されたIDが返ってくるはず。
(エンティティがイミュータブルの場合は戻り値で帰ってくる)
@Dao public interface PersonDomaDao { @Insert(sqlFile = true) Result<PersonEntity> insert(PersonEntity person); }
insert文はこんな感じ。
idは自動採番なので除外したSQL文にした。
INSERT INTO person( name, age ) VALUES ( /* name */'hoge', /* age */1 )
Entityはこんな感じ。
主キー予定のものに GeneratedValue
をつけてIDを採番する。
@Entity(immutable = true) @Table(name = "person") data class PersonEntity( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Int, val name: String, val age: Int )
このとき、idはnull許可じゃないので、初期値として適当に値(例えば12345とか)を入れておく。
(かなりお行儀が悪いが…)
んで、戻り値を見てみると、idに初期値として設定した値(12345)が返ってくる。
しかしDB側を見てみると、問題なく正しいシーケンス番号が登録されている。
何かが、おかしい…
解決編
うーん、よく考えるといらないことをいろいろしている。
その辺をただせばうまく動きました。
原因その1
毎度ながら公式を見なさいという事案でした。
(ドキュメントが最近英語対応中っぽく、ja->enでURLが違うので検索結果から入ると軒並みNotfoundになってる気がする)
これの通り、IDには null
もしくは 0未満の値
を設定してinsertに渡してあげないといけないのでした。
なのでこんな感じに直したら無事採番されました。
@Entity(immutable = true) @Table(name = "person") data class PersonEntity( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Int? = null, val name: String, val age: Int )
Kotlinのベストプラクティスのところでもidがnull許可になっててなんでやねんと思ってたけど、そういうことだったんですね…
Kotlin サポート — Doma ドキュメント
原因その2
外部のSQLファイルを使っていると採番されない。
これはちゃんと調べてないので、もしかしたら採番する方法があるのかもしれないです。
@Dao public interface PersonDomaDao { @Insert Result<PersonEntity> insert(PersonEntity person); }
エンティティのidをnull許可にすることで、idをわざわざなくしたお手製SQLファイルは不要になる。
なんだかコード的にもスッキリ。
これがKotlinのベストプラクティスの力…