Android 房间中的实体列表关系
Entity list relationships in Android Room
我正在尝试加载实体子列表,但我想避免进行 2 次查询。
我正在考虑在 TypeConverter 中进行查询,但我真的不知道这是否是个好主意。
我的实体:
@Entity
class Region(
@PrimaryKey(autoGenerate = true)
var id: Int = 0,
var name: String = "",
var locales: List<Locale> = listOf())
@Entity(foreignKeys = arrayOf(ForeignKey(
entity = Region::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("regionId"),
onDelete = CASCADE,
onUpdate = CASCADE
)))
class Locale(
@PrimaryKey(autoGenerate = true)
var id: Int = 0,
var regionId: Int = 0,
var name: String = "")
DAO:
@Dao
interface RoomRegionDao{
@Insert
fun insert(region: Region)
@Delete
fun delete(region: Region)
@Query("select * from region")
fun selectAll(): Flowable<List<Region>>
}
@Dao
interface RoomLocaleDao{
@Insert
fun insert(locale: Locale)
@Query("select * from locale where regionId = :arg0")
fun selectAll(regionId: Int): List<Locale>
}
数据库:
@Database(entities = arrayOf(Region::class, Locale::class), version = 1)
@TypeConverters(RoomAppDatabase.Converters::class)
abstract class RoomAppDatabase : RoomDatabase() {
abstract fun regionDao(): RoomRegionDao
abstract fun localeDao(): RoomLocaleDao
inner class Converters {
@TypeConverter
fun toLocales(regionId: Int): List<Locale> {
return localeDao().selectAll(regionId)
}
@TypeConverter
fun fromLocales(locales: List<Locale>?): Int {
locales ?: return 0
if (locales.isEmpty()) return 0
return locales.first().regionId
}
}
}
它不起作用,因为不能使用内部 class 作为转换器 class。
- 这个方法好吗?
- 当我执行
RoomRegionDao.selectAll
时,如何在区域实体中自动加载 "locales list"?
我认为 TypeConverter
仅适用于静态方法。
我是根据 here and here
中的例子说的
来自关系部分here:
"Because SQLite is a relational database, you can specify relationships between objects. Even though most ORM libraries allow entity objects to reference each other, Room explicitly forbids this."
所以我想最好是在 locales
属性 上添加 @Ignore
并在 RoomLocaleDao
上创建一个方法,即插入 List<Locale>
并调用它插入区域后。
插入Region的方法可以returninserted id.
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 instead.
(https://developer.android.com/topic/libraries/architecture/room.html#daos-convenience)
你可以得到你所有的 Regions
机智列表 Locales
在每个 Region
中只需要一个 Query
.
您需要做的就是像这样创建一个新的 Relation
:
data class RegionWithLocale(
@Embedded
val region: Region,
@Relation(
parentColumn = "id",
entity = Locale::class,
entityColumn = "regionId"
)
val locales: List<Locale>
)
而后者在你的 Dao
中得到这样的关系:
@Query("SELECT * FROM region WHERE id IS :regionId")
fun getRegions(regionId: Int): LiveData<RegionWithLocale>
@Query("SELECT * FROM region")
fun getAllRegions(): LiveData<List<RegionWithLocale>>
这个解决方案对我有用
ListConvert.kt
class ListConverter
{
companion object
{
var gson = Gson()
@TypeConverter
@JvmStatic
fun fromTimestamp(data: String?): List<Weather>?
{
if (data == null)
{
return Collections.emptyList()
}
val listType = object : TypeToken<List<String>>() {}.type
return gson.fromJson(data, listType)
}
@TypeConverter
@JvmStatic
fun someObjectListToString(someObjects: List<Weather>?): String?
{
return gson.toJson(someObjects)
}
}
}
我实体中的 属性
@SerializedName("weather")
@TypeConverters(ListConverter::class)
val weather: List<Weather>,
我正在尝试加载实体子列表,但我想避免进行 2 次查询。
我正在考虑在 TypeConverter 中进行查询,但我真的不知道这是否是个好主意。
我的实体:
@Entity
class Region(
@PrimaryKey(autoGenerate = true)
var id: Int = 0,
var name: String = "",
var locales: List<Locale> = listOf())
@Entity(foreignKeys = arrayOf(ForeignKey(
entity = Region::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("regionId"),
onDelete = CASCADE,
onUpdate = CASCADE
)))
class Locale(
@PrimaryKey(autoGenerate = true)
var id: Int = 0,
var regionId: Int = 0,
var name: String = "")
DAO:
@Dao
interface RoomRegionDao{
@Insert
fun insert(region: Region)
@Delete
fun delete(region: Region)
@Query("select * from region")
fun selectAll(): Flowable<List<Region>>
}
@Dao
interface RoomLocaleDao{
@Insert
fun insert(locale: Locale)
@Query("select * from locale where regionId = :arg0")
fun selectAll(regionId: Int): List<Locale>
}
数据库:
@Database(entities = arrayOf(Region::class, Locale::class), version = 1)
@TypeConverters(RoomAppDatabase.Converters::class)
abstract class RoomAppDatabase : RoomDatabase() {
abstract fun regionDao(): RoomRegionDao
abstract fun localeDao(): RoomLocaleDao
inner class Converters {
@TypeConverter
fun toLocales(regionId: Int): List<Locale> {
return localeDao().selectAll(regionId)
}
@TypeConverter
fun fromLocales(locales: List<Locale>?): Int {
locales ?: return 0
if (locales.isEmpty()) return 0
return locales.first().regionId
}
}
}
它不起作用,因为不能使用内部 class 作为转换器 class。
- 这个方法好吗?
- 当我执行
RoomRegionDao.selectAll
时,如何在区域实体中自动加载 "locales list"?
我认为 TypeConverter
仅适用于静态方法。
我是根据 here and here
来自关系部分here:
"Because SQLite is a relational database, you can specify relationships between objects. Even though most ORM libraries allow entity objects to reference each other, Room explicitly forbids this."
所以我想最好是在 locales
属性 上添加 @Ignore
并在 RoomLocaleDao
上创建一个方法,即插入 List<Locale>
并调用它插入区域后。
插入Region的方法可以returninserted id.
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 instead. (https://developer.android.com/topic/libraries/architecture/room.html#daos-convenience)
你可以得到你所有的 Regions
机智列表 Locales
在每个 Region
中只需要一个 Query
.
您需要做的就是像这样创建一个新的 Relation
:
data class RegionWithLocale(
@Embedded
val region: Region,
@Relation(
parentColumn = "id",
entity = Locale::class,
entityColumn = "regionId"
)
val locales: List<Locale>
)
而后者在你的 Dao
中得到这样的关系:
@Query("SELECT * FROM region WHERE id IS :regionId")
fun getRegions(regionId: Int): LiveData<RegionWithLocale>
@Query("SELECT * FROM region")
fun getAllRegions(): LiveData<List<RegionWithLocale>>
这个解决方案对我有用
ListConvert.kt
class ListConverter
{
companion object
{
var gson = Gson()
@TypeConverter
@JvmStatic
fun fromTimestamp(data: String?): List<Weather>?
{
if (data == null)
{
return Collections.emptyList()
}
val listType = object : TypeToken<List<String>>() {}.type
return gson.fromJson(data, listType)
}
@TypeConverter
@JvmStatic
fun someObjectListToString(someObjects: List<Weather>?): String?
{
return gson.toJson(someObjects)
}
}
}
我实体中的 属性
@SerializedName("weather")
@TypeConverters(ListConverter::class)
val weather: List<Weather>,