Perbarui beberapa bidang tertentu dari suatu entitas di Android Room

123

Saya menggunakan pustaka persistensi ruang android untuk proyek baru saya. Saya ingin memperbarui beberapa bidang tabel. Saya telah mencoba seperti di Dao-

// Method 1:

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

Tetapi ketika saya mencoba memperbarui menggunakan metode ini maka itu memperbarui setiap bidang entitas yang cocok dengan nilai kunci utama objek wisata. Saya telah menggunakan@Query

// Method 2:

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

Ini berfungsi tetapi akan ada banyak pertanyaan dalam kasus saya karena saya memiliki banyak bidang di entitas saya. Saya ingin tahu bagaimana saya dapat memperbarui beberapa bidang (tidak semua) seperti di Method 1mana id = 1; (id adalah kunci utama yang dihasilkan secara otomatis).

// Entity:

@Entity
public class Tour {
    @PrimaryKey(autoGenerate = true)
    public long id;
    private String startAddress;
    private String endAddress;
    //constructor, getter and setter
}
Rasel
sumber
Cara memperbarui daftar di Tabel. Sebenarnya saya telah memasukkan daftar di Tabel oleh TypeConverter. Tetapi saat datang dengan pembaruan itu tidak berfungsi. Mohon sarankan, jika Anda pernah menghadapi masalah seperti ini.
Aman Gupta - SHOoTeR
@ AmanGupta-ShOoTeR Apakah Anda mendapatkan solusi untuk komentar di atas?
skygeek
Koleksiku Perpustakaan Persistensi Kripton berfungsi sangat mirip dengan perpustakaan Ruangan itu. Jika Anda ingin melihat bagaimana saya menyelesaikan masalah ini menggunakan Kripton, silakan kunjungi abubusoft.com/wp/2019/10/02/…
xcesco
@ AmanGupta-ShOoTeR Saya menghadapi masalah seperti itu saat memperbarui menggunakan '@Query'. Kemudian saya menggunakan '@Insert (onConflict = OnConflictStrategy.REPLACE)' dengan membuat objek dengan nilai kunci utama yang sama, bukan pembaruan dan berhasil
Rasel

Jawaban:

68

Saya ingin tahu bagaimana saya dapat memperbarui beberapa bidang (tidak semua) seperti metode 1 di mana id = 1

Gunakan @Query, seperti yang Anda lakukan di Metode 2.

kueri terlalu panjang dalam kasus saya karena saya memiliki banyak bidang di entitas saya

Kemudian miliki entitas yang lebih kecil. Atau, jangan perbarui kolom satu per satu, tetapi miliki interaksi yang lebih kasar dengan database.

IOW, tidak ada apa pun di Room itu sendiri yang akan melakukan apa yang Anda cari.

CommonsWare
sumber
Apakah mungkin untuk memperbarui tabel tanpa melewatkan parameter apa pun? Maksud saya menukar nilai boolean.
Wisnu TB
1
@VishnuTB: Jika Anda dapat membuat pernyataan SQL yang melakukan apa yang Anda inginkan, Anda harus dapat menggunakannya dengan @Query.
CommonsWare
@Commonsare mengerti. Saya ingin mengambil satu set baris dengan nilai sebenarnya boolean. tetapi Room arch tidak mengizinkan saya untuk memberikan true / false sebagai parameter. sebagai gantinya true =1,false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Wisnu TB
4
Room 2.2.0-alpha01 ( developer.android.com/jetpack/androidx/releases/… ) memperkenalkan parameter baru untuk @Update yang memungkinkan Anda menyetel entitas target. Ini seharusnya memungkinkan pembaruan parsial.
Jonas
84

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

Contoh:

Kesatuan:

@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);
}
Jurij Pitulja
sumber
4
Bisakah Anda menjelaskan ini lebih lanjut?
Michael
1
Dengan entity dari pertanyaan metode DAO akan terlihat seperti ini: @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
Maksud saya dalam solusi Anda :) Lebih baik menampilkannya di sana agar dilihat pengguna lain
Michael
oh, saya pikir sudah jelas. Diperbaiki sekarang.
Jurij Pitulja
14

Mulai Room 2.2.0 yang dirilis Oktober 2019, Anda dapat menentukan Entitas Target untuk pembaruan. Kemudian jika parameter pembaruan berbeda, Ruangan hanya akan memperbarui kolom entitas parsial. Contoh pertanyaan OP akan menunjukkan ini sedikit lebih jelas.

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

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

Perhatikan bahwa Anda harus membuat entitas parsial baru yang disebut TourUpdate, bersama dengan entitas Tur asli Anda dalam pertanyaan tersebut. Sekarang ketika Anda memanggil update dengan objek TourUpdate, itu akan memperbarui endAddress dan membiarkan nilai startAddress sama. Ini berfungsi sempurna bagi saya untuk kasus penggunaan metode insertOrUpdate di DAO saya yang memperbarui DB dengan nilai jarak jauh baru dari API tetapi membiarkan data aplikasi lokal di tabel saja.

georgiecasey
sumber
6

Anda dapat mencoba ini, tetapi kinerjanya mungkin sedikit lebih buruk:

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

Saya pikir Anda tidak perlu memperbarui hanya beberapa bidang tertentu. Perbarui seluruh data.

@Update kueri

Ini pada dasarnya adalah kueri yang diberikan. Tidak perlu membuat kueri baru.

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

Satu-satunya hal yang perlu Anda ketahui adalah 'id'. Misalnya, jika Anda hanya ingin memperbarui 'judul', Anda dapat menggunakan kembali 'konten' dan 'foto' dari data yang sudah dimasukkan. Dalam kode sebenarnya, gunakan seperti ini

val memo = Memo(id, title, content, byteArrayList)
memoViewModel.update(memo)
J. Naga
sumber
-3

Jika Anda perlu memperbarui informasi pengguna untuk ID pengguna tertentu "x",

  1. Anda perlu membuat kelas dbManager yang akan menginisialisasi database dalam konstruktornya dan bertindak sebagai mediator antara viewModel dan DAO Anda, dan juga.
  2. The ViewModel akan menginisialisasi sebuah instance dari DBManager untuk mengakses database. Kode tersebut akan terlihat seperti ini:

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

    Kemudian perbarui item pengguna Anda dengan cara ini, misalkan ID pengguna Anda 1122 dan nama pengguna adalah "xyz" yang harus diubah menjadi "zyx".

    Dapatkan userItem dari id 1122 User object

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

Ini adalah kode mentah, semoga dapat membantu Anda.

Selamat membuat kode

Kunal Parte
sumber
10
Anda benar-benar melakukan tindakan database dalam model tampilan ??? tuhan no tlg no ...: '(lihat saja nama model seharusnya langsung mengenai wajah Anda
mcfly
@mcfly, Mengapa melakukan operasi database dalam Model Tampilan dianggap buruk?
Daniel
Prinsip tanggung jawab tunggal rusak ya
mcfly