Android Room에서 엔티티의 특정 필드 업데이트


122

새 프로젝트에 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에 목록을 삽입했습니다. 그러나 업데이트와 함께 제공되는 동안 작동하지 않습니다. 이와 같은 문제에 직면했다면 제안하십시오.
Aman Gupta-ShOoTeR

@ AmanGupta-ShOoTeR 위의 의견에 대한 해결책을 얻었습니까?
스카이 긱

내 라이브러리 Kripton Persistence Library는 해당 Room 라이브러리와 매우 유사하게 작동합니다. Kripton을 사용하여이 문제를 해결하는 방법을 확인하려면 abubusoft.com/wp/2019/10/02/…를 방문하십시오 .
xcesco

@ AmanGupta-ShOoTeR '@Query'를 사용하는 업데이트에서 이러한 종류의 문제에 직면했습니다. 그런 다음 업데이트 대신 동일한 기본 키 값을 가진 개체를 만들어 '@Insert (onConflict = OnConflictStrategy.REPLACE)'를 사용했는데 작동했습니다
Rasel

답변:


68

ID = 1 인 방법 1과 같은 일부 필드 (전부는 아님)를 어떻게 업데이트 할 수 있는지 알고 싶습니다.

@Query방법 2에서와 같이를 사용하십시오 .

내 엔터티에 필드가 많기 때문에 내 경우에는 쿼리가 너무 깁니다.

그런 다음 더 작은 개체가 있습니다. 또는 필드를 개별적으로 업데이트하지 말고 대신 데이터베이스와보다 대략적으로 상호 작용하십시오.

IOW, Room 자체에는 원하는 것을 수행 할 수있는 것이 없습니다.


매개 변수를 전달하지 않고 테이블을 업데이트 할 수 있습니까? 부울 값을 바꾸는 것을 의미합니다.
Vishnu TB

1
@VishnuTB : 원하는 작업을 수행하는 SQL 문을 만들 수 있다면 @Query.
CommonsWare

@ CommonsWare가 가져 왔습니다. 부울 참 값으로 행 집합을 가져오고 싶었습니다. 그러나 룸 아치는 매개 변수로 참 / 거짓을 전달할 수 없었습니다. 대신 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/… )은 대상 엔티티를 설정할 수있는 @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 :

@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
더 설명해 주 시겠어요?
Michael

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
나는 당신의 솔루션에 의미 : 그것은 거기 다른 사용자가 볼 수 있도록해야하는 것이 좋습니다
마이클

오, 당연하다고 생각했습니다. 지금 수정되었습니다.
Jurij Pitulja

14

현재 룸 2.2.0 2019년 10월 발표, 당신은 업데이트 대상 법인을 지정할 수 있습니다. 그런 다음 업데이트 매개 변수가 다른 경우 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;
}

질문의 실제 Tour 엔터티와 함께 ​​TourUpdate라는 새 부분 엔터티를 만들어야합니다. 이제 TourUpdate 개체로 update를 호출하면 endAddress가 업데이트되고 startAddress 값은 그대로 유지됩니다. 이것은 API의 새로운 원격 값으로 DB를 업데이트하지만 로컬 앱 데이터를 테이블에 그대로 두는 DAO의 insertOrUpdate 메서드 사용 사례에 적합합니다.


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

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)

-3

특정 사용자 ID "x"에 대한 사용자 정보를 업데이트해야하는 경우,

  1. 생성자에서 데이터베이스를 초기화하고 viewModel과 DAO 사이의 중재자 역할을 하는 dbManager 클래스 를 만들어야합니다 .
  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);

    그런 다음이 방법으로 사용자 항목을 업데이트합니다. 사용자 ID가 1122이고 userName이 "xyz"이며 "zyx"로 변경되어야한다고 가정합니다.

    ID 1122 사용자 개체의 userItem 가져 오기

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

이것은 원시 코드입니다. 도움이되기를 바랍니다.

즐거운 코딩


10
당신은 정말 viewmodel에서 데이터베이스 작업을 수행합니다 ??? 어떤 PLZ 신이 ... '(단지 모델 이름은 단지 얼굴에서 당신을 공격해야 볼
맥 플라이

@mcfly, 뷰 모델에서 데이터베이스 작업을 수행하는 것이 왜 나쁜 것으로 간주됩니까?
Daniel

단일 책임 원칙이 깨졌습니다. yes
mcfly
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.