Tun*_*i_D 78 sqlite android android-room android-architecture-components
Android的Room持久性库慷慨地包含适用于对象或集合的@Insert和@Update注释.然而,我有一个用例(包含模型的推送通知)需要UPSERT,因为数据可能存在或可能不存在于数据库中.
Sqlite本身没有upsert,并且在这个SO问题中描述了变通方法.鉴于那里的解决方案,如何将它们应用于房间?
更具体地说,如何在Room中实现不会破坏任何外键约束的插入或更新?使用带onConflict = REPLACE的insert将导致onDelete调用该行的任何外键.在我的情况下,onDelete导致级联,重新插入行将导致其他表中的行与外键被删除.这不是预期的行为.
use*_*282 71
为了更优雅的方式,我建议两个选项:
insert使用IGNOREas 检查操作的返回值OnConflictStrategy(如果它等于-1则表示未插入行):
@Insert(onConflict = OnConflictStrategy.IGNORE)
long insert(Entity entity);
@Update(onConflict = OnConflictStrategy.IGNORE)
void update(Entity entity);
public void upsert(Entity entity) {
long id = insert(entity);
if (id == -1) {
update(entity);
}
}
Run Code Online (Sandbox Code Playgroud)
从处理异常insert的操作与FAIL为OnConflictStrategy:
@Insert(onConflict = OnConflictStrategy.FAIL)
void insert(Entity entity);
@Update(onConflict = OnConflictStrategy.FAIL)
void update(Entity entity);
public void upsert(Entity entity) {
try {
insert(entity);
} catch (SQLiteConstraintException exception) {
update(entity);
}
}
Run Code Online (Sandbox Code Playgroud)
yeo*_*seo 52
也许你可以让你的BaseDao像这样.
使用@Transaction保护upsert操作,并仅在插入失败时尝试更新.
@Dao
public abstract class BaseDao<T> {
/**
* Insert an object in the database.
*
* @param obj the object to be inserted.
* @return The SQLite row id
*/
@Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract long insert(T obj);
/**
* Insert an array of objects in the database.
*
* @param obj the objects to be inserted.
* @return The SQLite row ids
*/
@Insert(onConflict = OnConflictStrategy.IGNORE)
public abstract List<Long> insert(List<T> obj);
/**
* Update an object from the database.
*
* @param obj the object to be updated
*/
@Update
public abstract void update(T obj);
/**
* Update an array of objects from the database.
*
* @param obj the object to be updated
*/
@Update
public abstract void update(List<T> obj);
/**
* Delete an object from the database
*
* @param obj the object to be deleted
*/
@Delete
public abstract void delete(T obj);
@Transaction
public void upsert(T obj) {
long id = insert(obj);
if (id == -1) {
update(obj);
}
}
@Transaction
public void upsert(List<T> objList) {
List<Long> insertResult = insert(objList);
List<T> updateList = new ArrayList<>();
for (int i = 0; i < insertResult.size(); i++) {
if (insertResult.get(i) == -1) {
updateList.add(objList.get(i));
}
}
if (!updateList.isEmpty()) {
update(updateList);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Tun*_*i_D 39
我找不到会插入或更新的SQLite查询而不会对我的外键造成不必要的更改,所以我选择先插入,忽略冲突(如果它们发生),然后立即更新,再次忽略冲突.
insert和update方法受到保护,因此外部类只能查看和使用upsert方法.请记住,这不是真正的upsert,好像任何MyEntity POJOS都有空字段,它们将覆盖当前数据库中的内容.这对我来说不是一个警告,但它可能适用于您的应用程序.
@Insert(onConflict = OnConflictStrategy.IGNORE)
protected abstract void insert(List<MyEntity> entities);
@Update(onConflict = OnConflictStrategy.IGNORE)
protected abstract void update(List<MyEntity> entities);
@Transaction
public void upsert(List<MyEntity> entities) {
insert(models);
update(models);
}
Run Code Online (Sandbox Code Playgroud)
如果表格有多个栏,您可以使用
@Insert(onConflict = OnConflictStrategy.REPLACE)
替换一行。
这是 Kotlin 中的代码:
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(entity: Entity): Long
@Update(onConflict = OnConflictStrategy.REPLACE)
fun update(entity: Entity)
@Transaction
fun upsert(entity: Entity) {
val id = insert(entity)
if (id == -1L) {
update(entity)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
37422 次 |
| 最近记录: |