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_id
や prefix_ 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のときに必要になってくるらしい(まだやってない)