Room でも @Insert は row ID を戻り値にできる。

# 要旨
Room（Android の SQLite のオブジェクト マッピング ライブラリ）においても、アイテム追加時には SQLite の row ID を戻り値として取得できる。

```java
@Dao
public interface yourDao {

    @Insert
    void yourMethod1(Item item);  // 戻り値なし
    
    @Insert
    long yourMethod2(Item item);  // 戻り値あり
}
```

---
# 前提

* Android の公式ライブラリ [Room 1.0.0](https://android-developers.googleblog.com/2017/11/announcing-architecture-components-10.html)
* Android API: [android.database.sqlite](https://developer.android.com/reference/android/database/sqlite/package-summary.html)（SQLite3）

---
# ライブラリ Room
[ドキュメント](https://developer.android.com/training/data-storage/room/accessing-data.html#convenience-insert) によれば

>If the `@Insert` method receives only 1 parameter, it can return a `long`, which is the new **rowId** for the inserted item. If the parameter is an array or a collection, it should return `long[]` or `List<Long>` instead.

（なお[レファレンス](https://developer.android.com/reference/android/arch/persistence/room/Insert.html) には現時点記載なし）

---
つまり `@Insert` を付けたメソッドは、戻り値を以下から選べる。

* `void`
* `long`（アイテムひとつ追加の場合）
* `long[]` ないし `List<Long>`（複数追加の場合）

---
[思うに](https://android.googlesource.com/platform/frameworks/support/+/master/room/runtime/src/main/java/android/arch/persistence/room/EntityInsertionAdapter.java)以下が可能（メソッド名は自由）

```java:
@Dao
public interface yourDao {

    // ひとつ追加

    @Insert
    void yourMethod1a(Item item);  // 戻り値なし
    
    @Insert
    long yourMethod1b(Item item);  // 戻り値あり
    

    // 複数追加（パラメータが配列）

    @Insert
    void yourMethod2a(Item... items);
    
    @Insert
    long[] yourMethod2b(Item... items);
    
    @Insert
    List<Long> yourMethod2c(Item... items);
    

    // 複数追加（パラメータがリスト）

    @Insert
    void yourMethod3a(List<Item> list);
    
    @Insert
    long[] yourMethod3b(List<Item> list);
    
    @Insert
    List<Long> yourMethod3c(List<Item> list);

}
```

---
## 従来の [Android API](https://developer.android.com/training/data-storage/sqlite.html) と比較
[android.database.sqlite](https://developer.android.com/reference/android/database/sqlite/package-summary.html) における追加メソッドは

[SQLiteDatabase](https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#insert%28java.lang.String,%20java.lang.String,%20android.content.ContentValues%29)

```java
long insert (String table, String nullColumnHack, ContentValues values)
```
[SQLiteStatement](https://developer.android.com/reference/android/database/sqlite/SQLiteStatement.html#executeInsert%28%29)

```java:
long executeInsert ()
```
どちらも戻り値は long で、追加された行の row ID を返すと説明されている。
>**row ID** of the newly inserted row, or -1 if an error occurred

---

# 以降は row ID に関する補足

---
## SQLite の "row ID ありテーブル"
[Rowid Tables](https://www.sqlite.org/rowidtable.html) によれば

> Most tables in a typical SQLite database schema are **rowid tables**.

つまり通常ならテーブルはこのタイプ

---
## row ID とは
続けて row ID の説明あり
> Rowid tables are distinguished by the fact that they all have a **unique, non-NULL, signed 64-bit integer rowid** that is used as the access key for the data in the underlying B-tree storage engine.

---
つまり SQLite の rowid テーブルの row ID は

* 一意的
* 符号付き64ビット整数（Java の long に相当）
* 非 NULL（主キーにふさわしい）

---
## 主キーに NULL
他方 SQLite の [`CREATE TABLE`](https://www.sqlite.org/lang_createtable.html#primkeyconst) によれば
> According to the SQL standard, PRIMARY KEY should always imply NOT NULL. Unfortunately, due to a bug in some early versions, this is not the case in SQLite. Unless the column is an **INTEGER PRIMARY KEY** or the table is a WITHOUT ROWID table or the column is declared NOT NULL, **SQLite allows NULL values in a PRIMARY KEY column.** SQLite could be fixed to conform to the standard, but doing so might break legacy applications. Hence, it has been decided to merely document the fact that SQLite allowing NULLs in most PRIMARY KEY columns.

---
つまり SQLite の場合、普通の主キーであれば **NULL 値も可**。既存アプリとの整合を優先させるため同バグの修正が見送られたため。

ちなみに `INTEGER PRIMARY KEY` の場合は **NULL なし**。 row ID との関係は後述。

---
## `INTEGER PRIMARY KEY` とは
ふたたび SQLite の [`CREATE TABLE`](https://www.sqlite.org/lang_createtable.html#rowid) によれば
>..., if a **rowid table** has a primary key that consists of a **single column** and the declared type of that column is **"INTEGER"** in any mixture of upper and lower case, then **the column becomes an alias for the rowid.** Such a column is usually referred to as an **"integer primary key"**. A PRIMARY KEY column only becomes an integer primary key if the declared type name is exactly "INTEGER".

---
つまり

* rowid テーブルであり
* その主キーがカラムひとつで
* データ型が INTEGER であれば

そのカラムは row ID の別名となる。これを `integer primary key` と呼ぶ。