更新 android 房间中实体的某些特定字段
Update some specific field of an entity in android Room
我正在为我的新项目使用 android 房间持久性库。
我想更新 table 的某些字段。
我在 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
}
I want to know how can I update some field(not all) like method 1 where id = 1
使用 @Query
,就像您在方法 2 中所做的那样。
is too long query in my case because I have many field in my entity
然后有更小的实体。或者,不要单独更新字段,而是与数据库进行更粗粒度的交互。
IOW,Room 本身没有任何东西可以满足您的需求。
更新 2020-09-15:Room 现在有部分实体支持,这有助于解决这种情况。有关更多信息,请参阅 。
<!-- 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);
}
如果您需要更新特定用户 ID 的用户信息 "x",
- 您需要创建一个 dbManager class 它将在其构造函数中初始化数据库并充当您的 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);
然后就这样更新你的用户项,假设你的用户 ID 是 1122,用户名是 "xyz",必须更改为 "zyx"。
获取id为1122的用户对象的userItem
User user = new user();
if(user.getUserId() == 1122){
user.setuserName("zyx");
userViewModel.updateUser(user);
}
这是一个原始代码,希望对您有所帮助。
编码愉快
你可以试试这个,但性能可能会差一点:
@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);
}
}
自 2019 年 10 月发布的 Room 2.2.0 起,您可以指定更新的目标实体。那么如果更新参数不同,Room 只会更新部分实体列。 OP 问题的示例将更清楚地说明这一点。
@Update(entity = Tour::class)
fun update(obj: TourUpdate)
@Entity
public class TourUpdate {
@ColumnInfo(name = "id")
public long id;
@ColumnInfo(name = "endAddress")
private String endAddress;
}
请注意,您必须创建一个名为 TourUpdate 的新部分实体,以及问题中的真实 Tour 实体。现在,当您使用 TourUpdate 对象调用更新时,它将更新 endAddress 并保持 startAddress 值不变。这非常适合我在我的 DAO 中使用 insertOrUpdate 方法的用例,该方法使用来自 API 的新远程值更新数据库,但将本地应用程序数据单独留在 table 中。
我认为您不需要只更新某些特定字段。
只需更新整个数据。
@Update query
基本上是一个给定的查询。无需进行一些新的查询。
@Dao
interface MemoDao {
@Insert
suspend fun insert(memo: Memo)
@Delete
suspend fun delete(memo: Memo)
@Update
suspend fun update(memo: Memo)
}
Memo.class
@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'。例如,如果您只想更新 'title',您可以从已插入的数据中重用 'content' 和 'photo' 。
在实际代码中,像这样使用
val memo = Memo(id, title, content, byteArrayList)
memoViewModel.update(memo)
我们需要您要更新的特定模型的主键。
例如:
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
在尝试解决我自己的类似问题后,我从 @PrimaryKey(autoGenerate = true)
更改为 int UUID
,我找不到如何编写迁移,所以我更改了 table 名称,这是一个简单的修复,如果你使用 personal/small 应用程序
您可以使用 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 房间持久性库。
我想更新 table 的某些字段。
我在 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
}
I want to know how can I update some field(not all) like method 1 where id = 1
使用 @Query
,就像您在方法 2 中所做的那样。
is too long query in my case because I have many field in my entity
然后有更小的实体。或者,不要单独更新字段,而是与数据库进行更粗粒度的交互。
IOW,Room 本身没有任何东西可以满足您的需求。
更新 2020-09-15:Room 现在有部分实体支持,这有助于解决这种情况。有关更多信息,请参阅
<!-- 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);
}
如果您需要更新特定用户 ID 的用户信息 "x",
- 您需要创建一个 dbManager class 它将在其构造函数中初始化数据库并充当您的 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);
然后就这样更新你的用户项,假设你的用户 ID 是 1122,用户名是 "xyz",必须更改为 "zyx"。
获取id为1122的用户对象的userItem
User user = new user(); if(user.getUserId() == 1122){ user.setuserName("zyx"); userViewModel.updateUser(user); }
这是一个原始代码,希望对您有所帮助。
编码愉快
你可以试试这个,但性能可能会差一点:
@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);
}
}
自 2019 年 10 月发布的 Room 2.2.0 起,您可以指定更新的目标实体。那么如果更新参数不同,Room 只会更新部分实体列。 OP 问题的示例将更清楚地说明这一点。
@Update(entity = Tour::class)
fun update(obj: TourUpdate)
@Entity
public class TourUpdate {
@ColumnInfo(name = "id")
public long id;
@ColumnInfo(name = "endAddress")
private String endAddress;
}
请注意,您必须创建一个名为 TourUpdate 的新部分实体,以及问题中的真实 Tour 实体。现在,当您使用 TourUpdate 对象调用更新时,它将更新 endAddress 并保持 startAddress 值不变。这非常适合我在我的 DAO 中使用 insertOrUpdate 方法的用例,该方法使用来自 API 的新远程值更新数据库,但将本地应用程序数据单独留在 table 中。
我认为您不需要只更新某些特定字段。 只需更新整个数据。
@Update query
基本上是一个给定的查询。无需进行一些新的查询。
@Dao
interface MemoDao {
@Insert
suspend fun insert(memo: Memo)
@Delete
suspend fun delete(memo: Memo)
@Update
suspend fun update(memo: Memo)
}
Memo.class
@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'。例如,如果您只想更新 'title',您可以从已插入的数据中重用 'content' 和 'photo' 。 在实际代码中,像这样使用
val memo = Memo(id, title, content, byteArrayList)
memoViewModel.update(memo)
我们需要您要更新的特定模型的主键。 例如:
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
在尝试解决我自己的类似问题后,我从 @PrimaryKey(autoGenerate = true)
更改为 int UUID
,我找不到如何编写迁移,所以我更改了 table 名称,这是一个简单的修复,如果你使用 personal/small 应用程序
您可以使用 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);