LoginSignup
24
18

More than 5 years have passed since last update.

逆引きRoom的ななにか(使ったところを加筆中)

Posted at

Entityクラスのなにか

宣言時の設定など

@Entity(tableName = "hoge_hoge", // Table名
          Index[] indices = [], // index
        foreignKeys = [ForeignKey( // 外部キー制約
                entity = SuperHoge::class, // 親のEntityクラスを指定
                String[] primaryKeys = [], // primaryKey指定
                parentColumns = arrayOf("id"), // 親Entityの対応するカラム
                childColumns = arrayOf("super_hoge_id"), // 自分の対応するカラム
                onDelete = ForeignKey.CASCADE) // Deleteされたときの動作
        ])
class HogeHogeEntity(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id", index = true)
    var id: Long = 0,
    @ColumnInfo(name = "username")
    var username: String?
    @ColumnInfo(name = "order")
    var order: Int?
)
  • index指定はカラムに直接アノテーションで指定できるので自分はそっちを使ってます。

POJO以外のData型を使うとき

  • コンバーター使う
  • RoomDatabase継承クラスのとこで以下のように指定
@TypeConverters(DateTypeConverter::class, StringListTypeConverter::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun myModelDao(): MyModelDao
}
  • Entityクラスで直接カラムを指定して書ける
@Entity(tableName = "hoge")
class HogeEntity(
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "id", index = true)
        var id: Long,
          @ColumnInfo(name = "tag_names")
        @TypeConverters(StringListTypeConverter::class) // Converterの指定
        var tagNames: List<String>?
)

Stringの配列

class StringListTypeConverter {
    @TypeConverter
    fun fromStringList(strings: List<String>?): String? {
        if (strings == null) {
            return null
        }

        val result = StringWriter()
        val json = JsonWriter(result)

        try {
            json.beginArray()

            strings.forEach {
                json.value(it)
            }

            json.endArray()
            json.close()
        } catch (e: IOException) {
            Crashlytics.logException(e)
        }

        return result.toString()
    }

    @TypeConverter
    fun toStringList(strings: String?): List<String>? {
        if (strings == null) {
            return null
        }

        val reader = StringReader(strings)
        val json = JsonReader(reader)
        val result = mutableListOf<String>()

        try {
            json.beginArray()

            while (json.hasNext()) {
                result.add(json.nextString())
            }

            json.endArray()
        } catch (e: IOException) {
            Crashlytics.logException(e)
        }

        return result
    }
}

Date型

class DateTypeConverter {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return if (value == null) null else Date(value)
    }

    @TypeConverter
    fun toTimestamp(date: Date?): Long? {
        return date?.*time*
    }
}

Enum型

class HogeStatusConverter {
    @TypeConverter
    fun fromString(typeString: String): HogeStatus {
        return BookshelfStatus.valueOf(typeString)
    }

    @TypeConverter
    fun fromStatus(status: HogeStatus): String {
        return status.toString()
    }
}

  • ハマったとこ enum class 側で値に @SerializedName(“in_progress”) みたいに指定してるとうまくいかない。そのときは valueOf()toString() しているところを切り替える

構造体?を内包する

  • @Embededを使う
class EmbededHoge {
    var id: Long
    var content: String
}
@Entity(tableName = "hoge")
class HogeEntity(
   ~~~~~~省略~~~~~
    @Embeded(prefix = "prefix_")
    var eHoge : EmbededHoge
)

これで EmbededHoge 構造体が eHoge にマッピングされます。

Relationalなマッピングではなく、あくまでもHogeEntity内にEmbededHogeのカラムが prefix_idprefix_ content といった形で追加されます。

Daoクラスのなにか

宣言時の設定など


@Dao
interface HogeDao {
    /* ===== SELECT ===== */
    @Query("select * from hoge order by order asc")
    fun getAll(): List<Hoge>

    @Query("select * from hoge where username=:username order by order asc, username asc")
    fun findByUserName(username: String): List<Hoge>

    /* ===== INSERT ===== */
    @Insert(onConflict = OnConflictStrategy.ROLLBACK) // コンフリクト時の設定
    fun insert(entity: HogeEntity)

    @Insert(onConflict = OnConflictStrategy.ABORT)
    fun insertAll(hogeEntities: List<HogeEntity>)

    /* ===== UPDATE ===== */
    @Update
    fun update(entity: HogeEntity)

    @Query("update hoge set order=:order where id=:id")
    fun updateOrder(id: Long, order: Int)

    /* ===== DELETE ===== */
    @Delete
    fun delete(entity: HogeEntity)

    @Query("delete from hoge where id in (:ids)")
    fun deleteInCategoryIds(ids: List<Long>)
}
  • 基本的には見たまま
  • username=:username みたいに変数は :hogehoge と書く
  • 配列のinsertやらdeleteもいける。primaryKeyないテーブルはとうまくいかない(と思う)

ちょっと複雑なことは基本 @Query で普通にsql書く

  • ただし、LiveData などで変更通知を監視しているときは注意。
    UPDATE/DELETE/INSERT をトリガーとしているのでQueryで更新系書くと変更通知されない

  • where in もいける。List 渡して where id in (:ids) みたいに書く

UpSertしたいとき

@Insert(onConflict = OnConflictStrategy.REPLACE) をinsertメソッドに追記。
レコードが存在したら置き換え、存在しなければインサートしてくれる。

  • 注意 以下のように外部キー制約が設定されているとHogeParent側でリプレースされたときにCASCADEでHogeEntityが消える(当たり前だけど
@Entity(tableName = "hoge",
    foreignKeys = [ForeignKey(
        entity = HogeParent::class,
        parentColumns = arrayOf("id"),
        childColumns = arrayOf("parent_id"),
        onDelete = ForeignKey.CASCADE)
])
class HogeEntity {
    ~~~~~~~~~
}

Databaseクラスのなにか

宣言時の設定など

@Database(
        entities = [ // Entityクラスをここに記載
            HogeEntity::class,
            FugaEntity::class
        ],
        version = 1, // Versionを記述。変わる場合は必要に応じてmigrateを書く
        exportSchema = false // schemaのExportを出力するか
) 
@TypeConverters(DateTypeConverter::class, StringListTypeConverter::class) // Converter
abstract class AppDatabase : RoomDatabase() {
    abstract fun hogeDao(): HogeDao // Daoを記載
    abstract fun fugaDao(): FugaDao
}

exportSchema について

  • = true にしておくとapp/schemasの下にschemaのjsonを吐いてくれるらしい
  • Gradleファイルにも以下のような設定が必要
    ※どこかで見て参考にさせていただきました。リソース明記できなくてすいません。
build.gradle
defaultConfig {
    ~~~~~~~~~~省略~~~~~~~~~~~
    javaCompileOptions {
        annotationProcessorOptions {
            arguments += [room.schemaLocation:$projectDir/schemas.toString()]
        }
    }
}
  • 他にもMigration Testのときに必要になってくるらしい(まだやってない)
24
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
18