【Android】Room DaoクラスのアノテーションとOnConflictStrategyまとめ

[Room]:https://developer.android.com/jetpack/androidx/releases/room?hl=ja
[Room  |  Android デベロッパー]:https://developer.android.com/jetpack/androidx/releases/room?hl=ja

[Room を使用してローカル データベースにデータを保存する  |  Android デベロッパー]:https://developer.android.com/training/data-storage/room?hl=ja

[Room DAO を使用してデータにアクセスする  |  Android デベロッパー]:https://developer.android.com/training/data-storage/room/accessing-data#convenience-insert

[OnConflictStrategy  |  Android デベロッパー]:https://developer.android.com/reference/androidx/room/OnConflictStrategy

[ROWIDの参照とINTEGER PRIMARY KEYとの関係 | SQLite入門]:https://www.dbonline.jp/sqlite/table/index8.html

[The ON CONFLICT Clause]:https://www.sqlite.org/rowidtable.html

# 概要
Androidアプリにてデータベース（SQLite）へのデータ保存・取得処理を実現する際に利用される[Room] 。

その[Room]を利用する手順 [^1] として

1. Roomをセットアップする（build.gradleに依存関係を追記）
2. RoomDatabaseクラス（データベースへのアクセスポイント）を作成する
3. Entityクラス（データベース内のテーブル ≒ 格納するデータ定義）を作成する
4. Daoクラス（データベースにアクセスに使用するメソッドを持つ）を作成する

以上が挙げられますが、今回は `4.Daoクラスを作成する` を取り上げ、
その中でもDaoクラスのメソッドに指定する`@Insert`などの`アノテーション`と`OnConflictStrategy`をメインにまとめていきます。

    
※ メモ兼ねての投稿で調査不十分な箇所があるかと存じますが、ご指摘いただけますと幸いです



# Daoクラスのメソッドに指定するアノテーション

いきなりですが、Daoクラスの作成例を以下に示します。
※ `Entity`という名前のEntityクラスを作成した前提
※ `Entity`はメンバとしてidを含む想定

```kotlin:
@Dao
interface EntityDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(entity: Entity): Long

    @Update(onConflict = OnConflictStrategy.REPLACE)
    fun update(entity: Entity): Int

    @Delete
    fun delete(entity: Entity): Int

    // @Queryに指定しているSQLは一例
    @Query("SELECT * from table_name WHERE id = :id")
    fun findById(id: String): Entiry?
    
}
```

上記の通り各メソッドにアノテーションを付与することで、[Room]がよしなに実装してくれます。


アノテーションの一覧はこちら。



|アノテーション  |説明  |指定できる戻り値|備考|
|:-:|:-:|:-:|:-:|
|<span>@</span>Insert  | 引数で渡したEntity（単体/配列/リスト）を挿入する|Void（Unit）、Long、Long[]、List`<Long>` |Long値は挿入されたデータに対応するRowId（=データを追加するごとに自動的に値が設定される非表示のカラム [^2] [^3] ）|
|<span>@</span>Update  | 引数で渡したEntity（単体/配列/リスト）を主キーを元に更新する|Void（Unit）、Int（更新された行数）|
|<span>@</span>Delete  | 引数で渡したEntity（単体/配列/リスト）を主キーを元に削除する|Void（Unit）、Int（削除された行数）|
|<span>@</span>Query   | アノテーションの"value"に対しクエリを指定して読み書き処理を実行できる|Void (Unit)をはじめとしたクエリに応じた戻り値|コンパイル時に検証されるため、クエリに問題があるとコンパイルエラーが発生。クエリの戻り値と対応列名とが一致しない場合、一部のフィールド名だけが一致している場合は警告を、1つも一致しない場合は、エラーが表示される|

※ 詳細な情報は[Room DAO を使用してデータにアクセスする  |  Android デベロッパー]を参照のこと


  
# OnConflictStrategyとは

さて、先ほどのDaoクラスのサンプルで<span>@</span>Insertと<span>@</span>Updateには **`onConflict=`** 指定がありました。

```
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(entity: Entity): Long

    @Update(onConflict = OnConflictStrategy.REPLACE)
    fun update(entity: Entity): Int

```

この**`onConflict=`**にOnConflictStrategyの指定を行うことで、データ挿入/更新時にコンフリクト（重複）が発生した場合の挙動を指定できます。

指定できるOnConflictStrategyの一覧はこちら。

|Strategyの種類  |挙動  |備考|
|:-:|:-:|:-: |
|**ABORT**  | トランザクションを中止しロールバックする |  <span>@</span>Insert、<span>@</span>UpdateでのデフォルトはABORT|
|~~FAIL~~  | トランザクションを失敗させる|Deprecatedなので、**代わりにABORTを使うこと** |
|**IGNORE** |  コンフリクトが発生しても無視し、処理を継続する|<span>@</span>Insertの場合：コンフリクトが発生すると挿入が実行されず-1が返る（RowIdがないため）|
|**REPLACE**  |  古いデータを置き換える ||
|~~ROLLBACK~~  | トランザクションをロールバックする|Deprecatedなので、**代わりにABORTを使うこと** |


備考にも記載していますが、 `@Insert`、`@Update`でのデフォルトは **`ABORT`** です。
=> `@Insert()`、`@Update()`のようにonConflict未指定の場合は **`ABORT`** が適用されます。

※ 詳細な情報は[OnConflictStrategy  |  Android デベロッパー]を参照のこと



# 参考
- [Room  |  Android デベロッパー]
- [Room を使用してローカル データベースにデータを保存する  |  Android デベロッパー]
- [Room DAO を使用してデータにアクセスする  |  Android デベロッパー]
- [OnConflictStrategy  |  Android デベロッパー]
- [ROWIDの参照とINTEGER PRIMARY KEYとの関係 | SQLite入門]
- [The ON CONFLICT Clause]





[^1]: [Room を使用してローカル データベースにデータを保存する  |  Android デベロッパー]
[^2]: [ROWIDの参照とINTEGER PRIMARY KEYとの関係 | SQLite入門]
[^3]: [The ON CONFLICT Clause]