更新android Room中实体的某些特定字段
Posted
技术标签:
【中文标题】更新android Room中实体的某些特定字段【英文标题】:Update some specific field of an entity in android Room 【发布时间】:2018-01-29 01:39:25 【问题描述】:我正在为我的新项目使用 android 房间持久性库。
我想更新表格的某些字段。
我在Dao
中尝试过 -
// Method 1:
@Dao
public interface TourDao
@Update
int updateTour(Tour tour);
但是当我尝试使用此方法进行更新时,它会更新与游览对象的主键值匹配的实体的每个字段。
我用过@Query
// Method 2:
@Query("UPDATE Tour SET endAddress = :end_address WHERE id = :tid")
int updateTour(long tid, String end_address);
它正在工作,但在我的情况下会有很多查询,因为我的实体中有很多字段。我想知道如何更新某些字段(不是全部),例如 Method 1
where id = 1; (id 是自动生成的主键)。
// Entity:
@Entity
public class Tour
@PrimaryKey(autoGenerate = true)
public long id;
private String startAddress;
private String endAddress;
//constructor, getter and setter
【问题讨论】:
如何更新表中的列表。实际上我已经通过 TypeConverter 在表中插入了列表。但是,虽然带有更新,但它不起作用。请提出建议,如果您遇到任何此类问题。 @AmanGupta-ShOoTeR 您对上述评论有什么解决方案吗? 我的库 Kripton Persistence 库的工作方式与那个 Room 库非常相似。如果你想看看我是如何使用 Kripton 解决这个问题的,请访问abubusoft.com/wp/2019/10/02/… @AmanGupta-ShOoTeR 我在使用“@Query”进行更新时遇到了此类问题。然后我通过创建具有相同主键值而不是更新的对象来使用“@Insert(onConflict = OnConflictStrategy.REPLACE)”并且它起作用了 【参考方案1】:我想知道如何更新一些字段(不是全部),例如方法 1 其中 id = 1
使用@Query
,就像在方法 2 中所做的那样。
在我的情况下查询太长,因为我的实体中有很多字段
然后有更小的实体。或者,不要单独更新字段,而是与数据库进行更粗粒度的交互。
IOW,Room 本身没有任何东西可以满足您的需求。
2020-09-15 更新:Room 现在有部分实体支持,可以帮助解决这种情况。请参阅this answer 了解更多信息。
【讨论】:
是否可以在不传递任何参数的情况下更新表格?我的意思是交换一个布尔值。 @VishnuTB:如果您可以创建一个执行您想要的 SQL 语句,您应该可以将它与@Query
一起使用。
@CommonsWare 明白了。我想获取一组具有布尔真值的行。但是房间拱门不允许我将真/假作为参数传递。而是true =1
, false=0
SELECT * FROM note_table WHERE isNoteArchived == 0
Room 2.2.0-alpha01 (developer.android.com/jetpack/androidx/releases/…) 为@Update 引入了一个新参数,可让您设置目标实体。这应该可以进行部分更新。【参考方案2】:
根据SQLite Update Docs:
<!-- language: lang-java -->
@Query("UPDATE tableName SET
field1 = :value1,
field2 = :value2,
...
//some more fields to update
...
field_N= :value_N
WHERE id = :id)
int updateTour(long id,
Type value1,
Type value2,
... ,
// some more values here
... ,
Type value_N);
例子:
实体:
@Entity(tableName = "orders")
public class Order
@NonNull
@PrimaryKey
@ColumnInfo(name = "order_id")
private int id;
@ColumnInfo(name = "order_title")
private String title;
@ColumnInfo(name = "order_amount")
private Float amount;
@ColumnInfo(name = "order_price")
private Float price;
@ColumnInfo(name = "order_desc")
private String description;
// ... methods, getters, setters
道:
@Dao
public interface OrderDao
@Query("SELECT * FROM orders")
List<Order> getOrderList();
@Query("SELECT * FROM orders")
LiveData<List<Order>> getOrderLiveList();
@Query("SELECT * FROM orders WHERE order_id =:orderId")
LiveData<Order> getLiveOrderById(int orderId);
/**
* Updating only price
* By order id
*/
@Query("UPDATE orders SET order_price=:price WHERE order_id = :id")
void update(Float price, int id);
/**
* Updating only amount and price
* By order id
*/
@Query("UPDATE orders SET order_amount = :amount, price = :price WHERE order_id =:id")
void update(Float amount, Float price, int id);
/**
* Updating only title and description
* By order id
*/
@Query("UPDATE orders SET order_desc = :description, order_title= :title WHERE order_id =:id")
void update(String description, String title, int id);
@Update
void update(Order order);
@Delete
void delete(Order order);
@Insert(onConflict = REPLACE)
void insert(Order order);
【讨论】:
你能解释一下吗? 使用问题 DAO 方法中的实体将如下所示:@Query("UPDATE Tour SET endAddress = :end_address, startAdress = :start_address WHERE id = :tid) int updateTour(long tid, String end_address,字符串 start_address); 我的意思是在你的解决方案中 :) 最好让其他用户看到 哦,我认为这很明显。现已修复。【参考方案3】:如果需要更新特定用户ID“x”的用户信息,
-
您需要创建一个 dbManager 类,该类将在其构造函数中初始化数据库,并充当 viewModel 和 DAO 之间的中介,以及 .
ViewModel 将初始化一个 dbManager 实例以访问数据库。 代码应如下所示:
@Entity
class User
@PrimaryKey
String userId;
String username;
Interface UserDao
//forUpdate
@Update
void updateUser(User user)
Class DbManager
//AppDatabase gets the static object o roomDatabase.
AppDatabase appDatabase;
UserDao userDao;
public DbManager(Application application )
appDatabase = AppDatabase.getInstance(application);
//getUserDao is and abstract method of type UserDao declared in AppDatabase //class
userDao = appDatabase.getUserDao();
public void updateUser(User user, boolean isUpdate)
new InsertUpdateUserAsyncTask(userDao,isUpdate).execute(user);
public static class InsertUpdateUserAsyncTask extends AsyncTask<User, Void, Void>
private UserDao userDAO;
private boolean isInsert;
public InsertUpdateBrandAsyncTask(BrandDAO userDAO, boolean isInsert)
this. userDAO = userDAO;
this.isInsert = isInsert;
@Override
protected Void doInBackground(User... users)
if (isInsert)
userDAO.insertBrand(brandEntities[0]);
else
//for update
userDAO.updateBrand(users[0]);
//try
// Thread.sleep(1000);
// catch (InterruptedException e)
// e.printStackTrace();
//
return null;
Class UserViewModel
DbManager dbManager;
public UserViewModel(Application application)
dbmanager = new DbMnager(application);
public void updateUser(User user, boolean isUpdate)
dbmanager.updateUser(user,isUpdate);
Now in your activity or fragment initialise your UserViewModel like this:
UserViewModel userViewModel = ViewModelProviders.of(this).get(UserViewModel.class);
然后以这种方式更新您的用户项,假设您的 userId 为 1122,userName 为“xyz”,必须将其更改为“zyx”。
获取 id 为 1122 的用户对象的 userItem
User user = new user(); if(user.getUserId() == 1122) user.setuserName("zyx"); userViewModel.updateUser(user);
这是一个原始代码,希望对您有所帮助。
愉快的编码
【讨论】:
您真的在视图模型中执行数据库操作???上帝不请不... :'( 只是查看模型名称应该只是打你的脸 @mcfly,为什么认为在 View Model 中进行数据库操作不好? 单一责任原则被打破了是【参考方案4】:你可以试试这个,但性能可能会差一点:
@Dao
public abstract class TourDao
@Query("SELECT * FROM Tour WHERE id == :id")
public abstract Tour getTour(int id);
@Update
public abstract int updateTour(Tour tour);
public void updateTour(int id, String end_address)
Tour tour = getTour(id);
tour.end_address = end_address;
updateTour(tour);
【讨论】:
【参考方案5】:截至 2019 年 10 月发布的 Room 2.2.0,您可以指定目标实体进行更新。那么如果更新参数不同,Room 只会更新部分实体列。 OP 问题的示例将更清楚地说明这一点。
@Update(entity = Tour::class)
fun update(obj: TourUpdate)
@Entity
public class Tour
@ColumnInfo(name = "id")
public long id;
@ColumnInfo(name = "note")
public String note;
@ColumnInfo(name = "endAddress")
public String endAddress;
public class TourUpdate
public long id;
public String note;
请注意,您必须创建一个名为 TourUpdate 的新部分实体,以及问题中的真实 Tour 实体。现在,当您使用 TourUpdate 对象调用 update 时,它将更新 endAddress 并保持 startAddress 值相同。这对我来说非常适合我在 DAO 中使用 insertOrUpdate 方法的用例,该方法使用来自 API 的新远程值更新数据库,但将本地应用程序数据单独留在表中。
【讨论】:
有趣的方式 这是在单个事务中更新多行和有限列的完美解决方案 根据the Room documentation,部分实体没有标注@Entity
或@ColumnInfo
,但是可以使用普通的POJO。
但在未使用 @Entity
和 @PrimaryKey
注释时会引发编译错误
@BabyishTank 这就是重点,这是用于数据库更新的。 endAddress 将在很长一段时间内保持它当前的值id
,只有note
会被更新。【参考方案6】:
我认为您不需要仅更新某些特定字段。 只需更新整个数据。
@Update 查询
基本上是给定的查询。无需进行一些新的查询。
@Dao
interface MemoDao
@Insert
suspend fun insert(memo: Memo)
@Delete
suspend fun delete(memo: Memo)
@Update
suspend fun update(memo: Memo)
备忘录类
@Entity
data class Memo (
@PrimaryKey(autoGenerate = true) val id: Int,
@ColumnInfo(name = "title") val title: String?,
@ColumnInfo(name = "content") val content: String?,
@ColumnInfo(name = "photo") val photo: List<ByteArray>?
)
您只需要知道“id”。例如,如果您只想更新“标题”,则可以重用 来自已插入数据的“内容”和“照片”。 在实际代码中,这样使用
val memo = Memo(id, title, content, byteArrayList)
memoViewModel.update(memo)
【讨论】:
还有什么需要做的吗?我有列信息名称,但按照示例 val memo = Memo(id, title, content, byteArrayList) 使用列信息名称对我不起作用。例如 Unresolved reference: dbMainLevel 其中 dbMainLevel 是列信息名称。【参考方案7】:我们需要您要更新的特定模型的主键。 例如:
private fun update(Name: String?, Brand: String?)
val deviceEntity = remoteDao?.getRemoteId(Id)
if (deviceEntity == null)
remoteDao?.insertDevice(DeviceEntity(DeviceModel = DeviceName, DeviceBrand = DeviceBrand))
else
DeviceDao?.updateDevice(DeviceEntity(deviceEntity.id,remoteDeviceModel = DeviceName, DeviceBrand = DeviceBrand))
在此函数中,我正在检查数据库中是否存在特定条目,如果存在则将主键作为 id 拉到此处并执行更新功能。
这是用于获取和更新记录的:
@Query("SELECT * FROM $DeviceDatabase.DEVICE_TABLE_NAME WHERE $DeviceDatabase.COLUMN_DEVICE_ID = :DeviceId LIMIT 1")
fun getRemoteDeviceId(DeviceId: String?): DeviceEntity
@Update(onConflict = OnConflictStrategy.REPLACE)
fun updatDevice(item: DeviceEntity): Int
【讨论】:
您调用 .getRemoteId(Id) 但您没有在那里传递任何 Id。顺便说一句,agruments 名称应该以小写开头【参考方案8】:在尝试解决我自己的类似问题后,我从 @PrimaryKey(autoGenerate = true)
更改为 int UUID
,我找不到如何编写我的迁移,所以我更改了表名,这是一个简单的修复,还可以如果您使用个人/小型应用程序
【讨论】:
【参考方案9】:您可以使用 URI 通过 id 更新数据库中的行
Tour tourEntity = new Tour();
tourEntity.end_address = "some adress";
tourEntity.start_address= "some adress";
//tourEntity..... other fields
tourEntity.id = ContentUris.parseId(Uri.parse("content://" + BuildConfig.APPLICATION_ID + File.separator + id));
//get your updatemethod with abstract func in your database class (or with another way, wich you use in project)
int tourDaoUpdate = getInstance(context).tour().update(tourEntity);
您还应该在更新方法中添加 OnConflictStrategy
@Update(onConflict = OnConflictStrategy.REPLACE)
int updateTour(Tour tour);
【讨论】:
以上是关于更新android Room中实体的某些特定字段的主要内容,如果未能解决你的问题,请参考以下文章
Android Room 库错误:找不到字段的设置器。 (科特林)