Cập nhật một số trường cụ thể của một thực thể trong Android Room


123

Tôi đang sử dụng thư viện kiên trì phòng android cho dự án mới của mình. Tôi muốn cập nhật một số lĩnh vực của bảng. Tôi đã cố gắng như trong Dao-

// Method 1:

@Dao
public interface TourDao {
    @Update
    int updateTour(Tour tour);
}

Nhưng khi tôi cố gắng cập nhật bằng phương pháp này thì nó sẽ cập nhật mọi trường của thực thể mà nó khớp với giá trị khóa chính của đối tượng tour. tôi đã sử dụng@Query

// Method 2:

@Query("UPDATE Tour SET endAddress = :end_address WHERE id = :tid")
int updateTour(long tid, String end_address);

Nó đang hoạt động nhưng sẽ có nhiều truy vấn trong trường hợp của tôi vì tôi có nhiều trường trong thực thể của mình. Tôi muốn biết làm thế nào tôi có thể cập nhật một số trường (không phải tất cả) như Method 1where id = 1; (id là khóa chính tự động tạo).

// Entity:

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

Cách cập nhật danh sách trong Bảng. Trên thực tế, tôi đã chèn danh sách trong Table by TypeConverter. Nhưng trong khi cập nhật nó không hoạt động. Vui lòng đề xuất, nếu bạn gặp phải bất kỳ vấn đề nào như thế này.
Aman Gupta - ShOoTeR

@ AmanGupta-ShOoTeR Bạn có nhận được giải pháp nào cho nhận xét trên không?
skygeek

Thư viện Kripton Persistence Library của tôi hoạt động khá giống với thư viện Room đó. Nếu bạn muốn xem cách tôi giải quyết vấn đề này bằng cách sử dụng Kripton, vui lòng truy cập abubusoft.com/wp/2019/10/02/…
xcesco

@ AmanGupta-ShOoTeR Tôi đã gặp phải những loại vấn đề như vậy khi cập nhật bằng '@Query'. Sau đó, tôi sử dụng '@Insert (onConflict = OnConflictStrategy.REPLACE)' bằng cách tạo một đối tượng có cùng giá trị khóa chính thay vì cập nhật và nó đã hoạt động
Rasel 3/12/19

Câu trả lời:


68

Tôi muốn biết làm cách nào để cập nhật một số trường (không phải tất cả) như phương pháp 1 trong đó id = 1

Sử dụng @Query, như bạn đã làm trong Phương pháp 2.

là truy vấn quá dài trong trường hợp của tôi vì tôi có nhiều trường trong thực thể của mình

Sau đó, có các thực thể nhỏ hơn. Hoặc, không cập nhật các trường riêng lẻ mà thay vào đó là các tương tác chi tiết hơn với cơ sở dữ liệu.

IOW, không có gì trong Room tự nó sẽ làm được những gì bạn tìm kiếm.


Có thể cập nhật bảng mà không cần chuyển bất kỳ tham số nào không? Ý tôi là hoán đổi giá trị boolean.
Vishnu TB

1
@VishnuTB: Nếu bạn có thể tạo câu lệnh SQL thực hiện những gì bạn muốn, bạn sẽ có thể sử dụng nó với @Query.
CommonsWare

@CommonsWare đã hiểu. Tôi muốn tìm nạp một tập hợp các hàng có giá trị thực boolean. nhưng Room Arch không cho phép tôi chuyển true / false làm tham số. thay vào đó true =1,false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Vishnu TB

4
Room 2.2.0-alpha01 ( developer.android.com/jetpack/androidx/releases/… ) đã giới thiệu một tham số mới cho @Update cho phép bạn đặt thực thể mục tiêu. Điều này sẽ làm cho cập nhật một phần có thể.
Jonas

84

Theo Tài liệu cập nhật 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);

Thí dụ:

Thực thể:

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

@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
Bạn có thể giải thích thêm về điều này?
Michael

1
Với thực thể từ câu hỏi, phương thức DAO sẽ giống như sau: @Query ("CẬP NHẬT Tour SET endAddress =: end_address, startAdress =: start_address WHERE id =: tid) int updateTour (long tid, String end_address, String start_address);
Jurij Pitulja

1
Tôi có nghĩa là trong giải pháp của bạn :) Nó tốt hơn để có nó ở đó cho những người dùng khác để xem
Michael

ồ, tôi nghĩ đó là điều hiển nhiên. Đã sửa ngay.
Jurij Pitulja

14

Kể từ khi Room 2.2.0 phát hành vào tháng 10 năm 2019, bạn có thể chỉ định Đối tượng mục tiêu để cập nhật. Sau đó, nếu tham số cập nhật khác, Room sẽ chỉ cập nhật các cột thực thể một phần. Ví dụ cho câu hỏi OP sẽ cho thấy điều này rõ ràng hơn một chút.

@Update(entity = Tour::class)
fun update(obj: TourUpdate)

@Entity
public class TourUpdate {
    @ColumnInfo(name = "id")
    public long id;
    @ColumnInfo(name = "endAddress")
    private String endAddress;
}

Lưu ý rằng bạn phải tạo một thực thể một phần mới có tên là TourUpdate, cùng với thực thể Tour thực của bạn trong câu hỏi. Bây giờ khi bạn gọi cập nhật với một đối tượng TourUpdate, nó sẽ cập nhật endAddress và giữ nguyên giá trị startAddress. Điều này hoạt động hoàn hảo đối với tôi vì tôi sử dụng phương thức insertOrUpdate trong DAO của tôi để cập nhật DB với các giá trị từ xa mới từ API nhưng vẫn để dữ liệu ứng dụng cục bộ trong bảng.


6

Bạn có thể thử cách này, nhưng hiệu suất có thể kém hơn một chút:

@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

Tôi nghĩ rằng bạn không cần phải cập nhật chỉ một số lĩnh vực cụ thể. Chỉ cần cập nhật toàn bộ dữ liệu.

@Update truy vấn

Về cơ bản nó là một truy vấn nhất định. Không cần phải thực hiện một số truy vấn mới.

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

Điều duy nhất bạn cần biết là 'id'. Ví dụ: nếu bạn chỉ muốn cập nhật 'tiêu đề', bạn có thể sử dụng lại 'nội dung' và 'ảnh' từ dữ liệu đã được chèn. Trong mã thực, sử dụng như thế này

val memo = Memo(id, title, content, byteArrayList)
memoViewModel.update(memo)

-3

Nếu bạn cần cập nhật thông tin người dùng cho một ID người dùng cụ thể "x",

  1. bạn cần tạo một lớp dbManager sẽ khởi tạo cơ sở dữ liệu trong phương thức khởi tạo của nó và hoạt động như một trung gian giữa viewModel và DAO của bạn, đồng thời.
  2. Các ViewModel sẽ khởi tạo một thể hiện của dbManager để truy cập cơ sở dữ liệu. Mã sẽ trông như thế này:

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

    Sau đó, chỉ cần cập nhật mục người dùng của bạn theo cách này, giả sử userId của bạn là 1122 và userName là "xyz" phải được thay đổi thành "zyx".

    Nhận một userItem của id 1122 Đối tượng người dùng

User user = new user();
 if(user.getUserId() == 1122){
   user.setuserName("zyx");
   userViewModel.updateUser(user);
 }

Đây là một mã thô, hy vọng nó sẽ giúp bạn.

Viết mã vui vẻ


10
Bạn thực sự thực hiện hành động cơ sở dữ liệu trong một mô hình xem ??? thần không plz không ...: '(chỉ cần xem tên mô hình chỉ nên đánh vào mặt bạn
McFly

@mcfly, Tại sao hoạt động cơ sở dữ liệu trong View Model bị coi là không tốt?
Daniel

Nguyên tắc khả năng đáp ứng đơn bị phá vỡ vâng
mcfly
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.