Обновить определенное поле объекта в Android Room

124

Я использую библиотеку сохраняемости комнаты 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 1where id = 1; (id - это автоматически сгенерированный первичный ключ).

// Entity:

@Entity
public class Tour {
    @PrimaryKey(autoGenerate = true)
    public long id;
    private String startAddress;
    private String endAddress;
    //constructor, getter and setter
}
Rasel
источник
Как обновить список в Табл. На самом деле я вставил список в таблицу с помощью TypeConverter. Но пока идет обновление, он не работает. Пожалуйста, предложите, если вы столкнулись с подобной проблемой.
Аман Гупта - ShOoTeR
@ AmanGupta-ShOoTeR Получили ли вы какое-либо решение для комментария выше?
skygeek 05
Моя библиотека Kripton Persistence Library работает очень похоже на эту библиотеку Room. Если вы хотите узнать, как я решил эту проблему с помощью Kripton, посетите abubusoft.com/wp/2019/10/02/…
xcesco
@ AmanGupta-ShOoTeR Я столкнулся с такими проблемами при обновлении с помощью «@Query». Тогда я использовал «@Insert (onConflict = OnConflictStrategy.REPLACE)», создав объект с тем же значением первичного ключа вместо обновления , и она работала
Rasel

Ответы:

68

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

Используйте @Query, как в методе 2.

это слишком длинный запрос в моем случае, потому что у меня много полей в моей сущности

Затем создайте более мелкие организации. Или не обновляйте поля по отдельности, а вместо этого более детально взаимодействуйте с базой данных.

IOW, в самой комнате нет ничего, что могло бы делать то, что вы ищете.

CommonsWare
источник
Можно ли обновить таблицу без передачи каких-либо параметров? Я имею в виду замену логического значения.
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, который позволяет вам установить целевой объект. Это должно сделать возможными частичные обновления.
Jonas
86

Согласно документации по обновлению 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:

@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);
Юрий Питулья
1
Я имел в виду в вашем решении :) Лучше, чтобы это было там, чтобы другие пользователи могли видеть
Майкл
о, я думал это очевидно. Исправлено сейчас.
Jurij Pitulja
14

Начиная с Room 2.2.0, выпущенного в октябре 2019 года, вы можете указать целевую сущность для обновлений. Затем, если параметр обновления отличается, 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 в вопросе. Теперь, когда вы вызываете update с объектом TourUpdate, он обновит endAddress и оставит значение startAddress прежним. Это идеально подходит для меня в моем случае использования метода insertOrUpdate в моем DAO, который обновляет БД новыми удаленными значениями из API, но оставляет только данные локального приложения в таблице.

georgiecasey
источник
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);
    }
}
SUPERYAO
источник
2

Я думаю, вам не нужно обновлять только какое-то конкретное поле. Просто обновите все данные.

@Update запрос

По сути, это заданный запрос. Не нужно делать новый запрос.

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

Единственное, что вам нужно знать, - это id. Например, если вы хотите обновить только «заголовок», вы можете повторно использовать «контент» и «фото» из уже вставленных данных. В реальном коде используйте вот так

val memo = Memo(id, title, content, byteArrayList)
memoViewModel.update(memo)
J.Dragon
источник
-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».

    Получить userItem с идентификатором 1122 Пользовательский объект

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

Это необработанный код, надеюсь, он вам поможет.

Удачного кодирования

Кунал Парте
источник
10
Вы действительно делаете действия с базами данных во вьюмодели ??? God no plz no ...: '(просто
посмотрите,
@mcfly, почему операции с базой данных в View Model считается плохим?
Дэниел
Принцип единой ответственности нарушен да
mcfly