Android Room库@Update注解更新指定字段失效问题求助
问题分析与解决方案
你遇到的问题核心在于Room的@Update注解是通过主键匹配来定位要更新的行,而你的TemplateEntity使用了templateParentUid和templateName作为组合主键。
看你当前的更新逻辑:你创建了一个全新的TemplateEntity,只设置了templateParentUid和新的templateName("test"),但这个组合值并不是数据库中现有行的主键(现有行的主键是旧的templateName + templateParentUid)。Room找不到匹配的行,自然不会执行更新操作——即使onComplete被调用,也只是代表数据库操作执行完成,而非更新成功命中了目标行。
修复步骤
1. 在Dao中添加查询方法
首先需要根据旧的主键(原templateParentUid+原templateName)查询出数据库中对应的实体:
@Query("SELECT * FROM template WHERE templateParentUid = :parentUid AND templateName = :oldTemplateName") TemplateEntity getTemplateByParentAndName(int parentUid, String oldTemplateName);
2. 修改更新逻辑
先查询出目标实体,修改字段后再执行更新:
public void updateTemplate(final int templateParentUid, final String oldTemplateName, final String newTemplateName, final DatabaseCallback<TemplateEntity> databaseCallback) { Completable .fromAction(() -> { // 1. 查询要更新的实体 TemplateEntity targetTemplate = db.soleHomeDao().getTemplateByParentAndName(templateParentUid, oldTemplateName); if (targetTemplate == null) { throw new RuntimeException("未找到要更新的模板:parentUid=" + templateParentUid + ", oldName=" + oldTemplateName); } // 2. 修改需要更新的字段 targetTemplate.setTemplateName(newTemplateName); // 3. 执行更新 db.soleHomeDao().updateTemplate(targetTemplate); }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new CompletableObserver() { @Override public void onSubscribe(@NonNull Disposable d) { compositeDisposable.add(d); LogUtils.d("updateTemplate -> onSubscribe"); } @Override public void onComplete() { databaseCallback.onUpdated(); LogUtils.d("updateTemplate -> onUpdated"); } @Override public void onError(@NonNull Throwable e) { databaseCallback.onError(e.getMessage()); LogUtils.d("updateTemplate -> onError e" + e.toString()); } }); }
3. 调整调用代码
调用时需要传入旧的templateName,让Room能定位到目标行:
DatabaseManager.getInstance(getContext()).updateTemplate( templateEntity.getTemplateParentUid(), templateEntity.getTemplateName(), // 传入旧的模板名称 "test", // 新的模板名称 new DatabaseCallback<TemplateEntity>() { @Override public void onUpdated() { super.onUpdated(); LogUtils.d("updateText -> onUpdated:"); getTemplateData(); } @Override public void onError(String err) { super.onError(err); LogUtils.d("updateText -> onError:" + err); } } );
额外说明
因为你将templateName作为主键的一部分,修改它本质上是修改主键值。Room的OnConflictStrategy.REPLACE策略在这种情况下会先删除旧的主键行,再插入新的主键行,这是符合SQLite对于主键冲突的处理逻辑的。只要你通过旧主键查询到了目标实体,修改后再更新,就能达到你想要的“修改templateName”的效果。
内容的提问来源于stack exchange,提问作者NoName
相关产品推荐
相关产品推荐

