更新Android Room中实体的某些特定字段


121

我正在为新项目使用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 1id = 1;(id是自动生成的主键)。

// Entity:

@Entity
public class Tour {
    @PrimaryKey(autoGenerate = true)
    public long id;
    private String startAddress;
    private String endAddress;
    //constructor, getter and setter
}

如何更新表中的列表。实际上,我已经通过TypeConverter在Table中插入了列表。但是在进行更新时无法正常工作。如果遇到任何此类问题,请提出建议。
阿曼古普塔

@ AmanGupta-ShOoTeR您对以上评论有任何解决方案吗?
skygeek

我的图书馆Kripton Persistence Library的工作原理与该Room库非常相似。如果您想了解我如何使用Kripton解决此问题,请访问abubusoft.com/wp/2019/10/02/…–
xcesco

@ AmanGupta-ShOoTeR我在使用“ @Query”进行更新时遇到了此类问题。然后,我通过创建具有相同主键值而不是更新的对象来使用'@Insert(onConflict = OnConflictStrategy.REPLACE)',它起作用了
Rasel

Answers:


67

我想知道如何更新某些字段(不是全部),例如方法1,其中id = 1

@Query,当你在方法2一样。

就我而言,查询时间太长,因为我的实体中有很多字段

然后有较小的实体。或者,不要单独更新字段,而是与数据库进行更粗粒度的交互。

IOW,房间本身没有任何东西可以满足您的需求。


是否可以在不传递任何参数的情况下更新表?我的意思是交换一个布尔值。
Vishnu TB

1
@VishnuTB:如果您可以创建执行所需操作的SQL语句,则应该可以将其与一起使用@Query
CommonsWare,

@CommonsWare知道了。我想获取一组布尔值为true的行。但Room arch不允许我传递true / false作为参数。相反true =1false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Vishnu TB

4
2.2.0-alpha01室(developer.android.com/jetpack/androidx/releases/…)为@Update引入了新参数,可用于设置目标实体。这样应该可以进行部分更新。
乔纳斯(Jonas)

84

根据SQLite更新文档

<!-- 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);
}

4
您能再解释一下吗?
迈克尔

1
对于问题中的实体,DAO方法将如下所示:@Query(“ UPDATE Tour SET endAddress =:end_address,startAdress =:start_address WHERE id =:tid)int updateTour(long tid,String end_address,String start_address);
Jurij Pitulja

1
我的意思是在你的解决方案:)最好是有它存在其他用户看到
迈克尔·

哦,我认为这很明显。立即修复。
朱里

13

从2019年10月发布的Room 2.2.0开始,您可以指定目标实体进行更新。然后,如果update参数不同,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对象调用update时,它将更新endAddress并使startAddress值保持不变。对于我在DAO中使用insertOrUpdate方法的用例而言,这非常适合我,该方法使用API​​中的新远程值更新数据库,但将本地应用程序数据保留在表中。


6

您可以尝试这样做,但性能可能会稍差一些:

@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);
    }
}

2

我认为您不需要仅更新某些特定字段。只需更新整个数据。

@更新查询

它基本上是一个给定的查询。无需进行一些新查询。

@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)

-3

如果您需要更新特定用户ID“ x”的用户信息,

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

这是原始代码,希望对您有所帮助。

快乐编码


10
您确实在视图模型中执行数据库操作?上帝没有PLZ没有...:'(只是视图模型名称应该打在你的脸上
mcfly 18/08/30

@mcfly,为什么在视图模型中执行数据库操作被认为很糟糕?
丹尼尔·

打破单一的责任原则是
mcfly
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.