【问题标题】:Update some specific field of an entity in android Room更新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)”并且它起作用了

标签: android sql-update android-room


【解决方案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”的用户信息,

  1. 您需要创建一个 dbManager 类,该类将在其构造函数中初始化数据库,并充当 viewModel 和 DAO 之间的中介,以及 .
  2. 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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多