如何在 Room 中插入一组可为空的实体?
How to insert a set of nullable entites in Room?
我有一个名为 City 的房间实体:
@Entity(tableName = "cities")
class City(
@PrimaryKey
@ColumnInfo(name = "unique_city_id")
val id: Long,
@ColumnInfo(name = "city_name")
val name: String,
@ColumnInfo(name = "city_code")
val code: String,
)
我有一个 class 类型的对象列表:
data class CoffeeHouse(
override val id: Long,
override val latitude: Double,
override val longitude: Double,
override val city: City?,
override val address: String,
)
我需要保存 CoffeeHouse 和 City classes。因为有很多相同的城市,所以我将咖啡馆列表映射到一组城市以仅获得唯一的城市:
val cities = coffeeHouses.map { it.city?.toPersistenceType() }.toSet()
(.toPersistenceType()
只是将域类型映射到持久性)
然后我使用这些 DAO 将 coffeeHouses
和 cities
插入到 Room 数据库中:
@Dao
abstract class CoffeeHouseDao(val cacheDatabase: CacheDatabase) {
private val cityDao = cacheDatabase.cityDao()
@Insert(onConflict = REPLACE)
abstract suspend fun insertAllCoffeeHouses(coffeeHouses: List<CoffeeHouse>)
@Transaction
open suspend fun insertAllCoffeeHousesInfo(
coffeeHouses: List<CoffeeHouse>,
cities: Set<City?>,
) {
insertAllCoffeeHouses(coffeeHouses)
cityDao.setCities(cities)
}
}
@Dao
interface CityDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun setCities(cities: Set<City?>)
问题是当我尝试插入 Set 应用时出现异常崩溃:
Uncaught exception java.lang.NullPointerException:
Attempt to invoke virtual method 'long com.coffeeapp.android.persistence.entity.City.getId()'
on a null object reference
stacktrace点在cities插入的那一行,所以我不明白如何正确。
发生这种情况是因为您已将 city 中的 ID 字段设置为该 table 的主键,并且它不能为空。
您可以尝试将注释更改为
@PrimaryKey(autoGenerate = true)
或者,如果您不想自动递增,则必须确保在插入城市时 ID 不为空。
我认为是因为 CofeeHouse 实体中的 city: City? 和 cities: Set 。尝试使它们不可为空。
要允许插入带有 null 的 a,您可以使用 :-
@Entity(tableName = "cities")
class City(
@PrimaryKey
@ColumnInfo(name = "unique_city_id")
val id: Long?, //<<<<<<<< ? ADDED
@ColumnInfo(name = "city_name")
val name: String,
@ColumnInfo(name = "city_code")
val code: String,
)
这样插入时会生成id。例如以下(为方便起见,基于减少)。
但是,REPLACE 冲突策略永远不会导致替换,因为 null 会生成唯一的 id.
我相信你想要的是城市名称、城市代码或两者(一起或独立)构成一个唯一的条目。
因此 :-
@Entity(
tableName = "cities",
indices = [
/*
probably just one of these all three is overkill
*/
Index(value = ["city_name"],unique = true),
Index(value = ["city_code"], unique = true),
Index(value = ["city_name","city_code"],unique = true)
]
)
class City(
@PrimaryKey
@ColumnInfo(name = "unique_city_id")
val id: Long?,
@ColumnInfo(name = "city_name")
val name: String,
@ColumnInfo(name = "city_code")
val code: String,
)
例如考虑以下内容:-
cityDao.setCities(setOf<City>(City(null,"Sydney","SYD1"),City(null,"New York","NY1")))
cityDao.setCities(setOf<City>(City(null,"Sydney","SYD1"),City(null,"New York","NY1")))
- 因此尝试添加同一组城市结果是:-
即第一次添加 id 为 1 和 2 的悉尼和纽约,第二次尝试由于删除原件的冲突而被替换,所以你最终得到 id 的 3 和 4。如果没有唯一索引,那么结果将是 4 行ID 为 1、2、3 和 4。
我有一个名为 City 的房间实体:
@Entity(tableName = "cities")
class City(
@PrimaryKey
@ColumnInfo(name = "unique_city_id")
val id: Long,
@ColumnInfo(name = "city_name")
val name: String,
@ColumnInfo(name = "city_code")
val code: String,
)
我有一个 class 类型的对象列表:
data class CoffeeHouse(
override val id: Long,
override val latitude: Double,
override val longitude: Double,
override val city: City?,
override val address: String,
)
我需要保存 CoffeeHouse 和 City classes。因为有很多相同的城市,所以我将咖啡馆列表映射到一组城市以仅获得唯一的城市:
val cities = coffeeHouses.map { it.city?.toPersistenceType() }.toSet()
(.toPersistenceType()
只是将域类型映射到持久性)
然后我使用这些 DAO 将 coffeeHouses
和 cities
插入到 Room 数据库中:
@Dao
abstract class CoffeeHouseDao(val cacheDatabase: CacheDatabase) {
private val cityDao = cacheDatabase.cityDao()
@Insert(onConflict = REPLACE)
abstract suspend fun insertAllCoffeeHouses(coffeeHouses: List<CoffeeHouse>)
@Transaction
open suspend fun insertAllCoffeeHousesInfo(
coffeeHouses: List<CoffeeHouse>,
cities: Set<City?>,
) {
insertAllCoffeeHouses(coffeeHouses)
cityDao.setCities(cities)
}
}
@Dao
interface CityDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun setCities(cities: Set<City?>)
问题是当我尝试插入 Set
Uncaught exception java.lang.NullPointerException:
Attempt to invoke virtual method 'long com.coffeeapp.android.persistence.entity.City.getId()'
on a null object reference
stacktrace点在cities插入的那一行,所以我不明白如何正确。
发生这种情况是因为您已将 city 中的 ID 字段设置为该 table 的主键,并且它不能为空。
您可以尝试将注释更改为
@PrimaryKey(autoGenerate = true)
或者,如果您不想自动递增,则必须确保在插入城市时 ID 不为空。
我认为是因为 CofeeHouse 实体中的 city: City? 和 cities: Set
要允许插入带有 null 的 a,您可以使用 :-
@Entity(tableName = "cities")
class City(
@PrimaryKey
@ColumnInfo(name = "unique_city_id")
val id: Long?, //<<<<<<<< ? ADDED
@ColumnInfo(name = "city_name")
val name: String,
@ColumnInfo(name = "city_code")
val code: String,
)
这样插入时会生成id。例如以下(为方便起见,基于减少)。
但是,REPLACE 冲突策略永远不会导致替换,因为 null 会生成唯一的 id.
我相信你想要的是城市名称、城市代码或两者(一起或独立)构成一个唯一的条目。
因此 :-
@Entity(
tableName = "cities",
indices = [
/*
probably just one of these all three is overkill
*/
Index(value = ["city_name"],unique = true),
Index(value = ["city_code"], unique = true),
Index(value = ["city_name","city_code"],unique = true)
]
)
class City(
@PrimaryKey
@ColumnInfo(name = "unique_city_id")
val id: Long?,
@ColumnInfo(name = "city_name")
val name: String,
@ColumnInfo(name = "city_code")
val code: String,
)
例如考虑以下内容:-
cityDao.setCities(setOf<City>(City(null,"Sydney","SYD1"),City(null,"New York","NY1")))
cityDao.setCities(setOf<City>(City(null,"Sydney","SYD1"),City(null,"New York","NY1")))
- 因此尝试添加同一组城市结果是:-
即第一次添加 id 为 1 和 2 的悉尼和纽约,第二次尝试由于删除原件的冲突而被替换,所以你最终得到 id 的 3 和 4。如果没有唯一索引,那么结果将是 4 行ID 为 1、2、3 和 4。