Оновіть певне поле сутності в android Room


122

Я використовую бібліотеку стійкості для android room для свого нового проекту. Я хочу оновити деяке поле таблиці. Я спробував, як у своєму 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де 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. Але хоч з оновленням це не працює. Підкажіть, якщо ви стикалися з будь-яким подібним питанням.
Аман Гупта - ShOoTeR

@ AmanGupta-ShOoTeR Ви отримали якесь рішення для коментаря вище?
skygeek

Моя бібліотека Криптон-бібліотека стійкості працює досить схоже на бібліотеку кімнат. Якщо ви хочете ознайомитись із тим, як я вирішую цю проблему за допомогою Kripton, відвідайте abubusoft.com/wp/2019/10/02/…
xcesco

@ AmanGupta-ShOoTeR Я стикався з подібними проблемами при оновленні за допомогою "@Query". Тоді я використовував «@Insert (onConflict = OnConflictStrategy.REPLACE)», створивши об'єкт з тим же значенням первинного ключа замість поновлення , і вона працювала
Rasel

Відповіді:


68

Я хочу знати, як я можу оновити якесь поле (не все), наприклад метод 1, де id = 1

Використовуйте так @Query, як ви робили в 2-му способі.

в моєму випадку занадто довгий запит, тому що у мене в області багато

Тоді є менші сутності. Або не оновлювати поля окремо, а натомість мати більш грубі взаємодії з базою даних.

IOW, в самій кімнаті немає нічого, що зробить те, чого ви прагнете.


Чи можливо оновити таблицю, не передаючи жодних параметрів? Я маю на увазі заміну булевого значення.
Vishnu TB

1
@VishnuTB: Якщо ви можете створити оператор SQL, який виконує те, що ви хочете, ви повинні мати можливість використовувати його @Query.
CommonsWare

@CommonsWare отримав це. Я хотів отримати набір рядків з булевим справжнім значенням. але арка кімнати не дозволила мені передати параметр true / false як параметр. замість цього true =1,false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Вішну TB

4
Кімната 2.2.0-alpha01 ( developer.android.com/jetpack/androidx/releases/… ) представила новий параметр для @Update, який дозволяє встановити цільову сутність. Це має зробити можливими часткові оновлення.
Йонас

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 (довгий tid, String end_address, String start_address);
Jurij Pitulja

1
Я мав на увазі у своєму рішенні :) Краще мати його там, щоб інші користувачі могли бачити
Майкл

о, я думав, що це очевидно. Виправлено зараз.
Юрій Пітуля

14

Станом на номер 2.2.0, випущений у жовтні 2019 року, ви можете вказати цільовий об’єкт для оновлень. Тоді якщо параметр оновлення інший, Room оновить лише часткові стовпці сутності. Приклад для питання про ОП покаже це дещо чіткіше.

@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 таким же. Це для мене ідеально підходить для мого використання методу insertOrUpdate в моєму DAO, який оновлює DB з новими віддаленими значеннями з 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

Якщо вам потрібно оновити інформацію про користувача для конкретного ідентифікатора користувача "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 Об'єкт користувача

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

Це необроблений код, сподіваємось, він вам допоможе.

Щасливе кодування


10
Ви дійсно робите дії з базами даних у моделі перегляду ??? God no plz no ...: '(просто перегляд назви моделі повинен просто вдарити тебе в обличчя
mcfly

@mcfly, чому вважається поганим виконувати операції з базою даних у моделі перегляду?
Даніель

принцип єдиної відповідальності порушений так
mcfly
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.