Androidルームでエンティティの特定のフィールドを更新する


121

新しいプロジェクトで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
}

テーブルのリストを更新する方法。実際には、TypeConverterによってテーブルにリストを挿入しました。しかし、アップデートが付属している間は機能しません。このような問題に直面した場合は、提案してください。
アマングプタ-ShOoTeR 2018年

@ AmanGupta-ShOoTeR上記のコメントに対する解決策はありましたか?
skygeek

私のライブラリKripton Persistence Libraryは、そのRoomライブラリと非常によく似ています。Kriptonを使用してこの問題を解決する方法を確認したい場合は、abubsoft.com
wp /

@ AmanGupta-ShOoTeR「@Query」を使用した更新でこのような問題に直面しました。次に、「@ Insert(onConflict = OnConflictStrategy.REPLACE)」を使用して、更新ではなく同じ主キー値を持つオブジェクトを作成し、それが機能しました
Rasel

回答:


68

メソッド1のようにいくつかのフィールド(すべてではない)をどのように更新できるか知りたい

@Query方法2と同様に、を使用します。

私のエンティティには多くのフィールドがあるため、私の場合はクエリが長すぎます

次に、エンティティを小さくします。または、フィールドを個別に更新せずに、データベースとのやり取りをより粗くします。

IOW、Room自体には、あなたが求めていることを行うものはありません。


パラメータを渡さずにテーブルを更新することは可能ですか?ブール値を入れ替えることを意味します。
Vishnu TB

1
@VishnuTB:必要なことを実行するSQLステートメントを作成できれば、それをで使用できるはず@Queryです。
CommonsWare

@CommonsWareはそれを手に入れました。私はブール値の真の値を持つ行のセットをフェッチしたかったのです。しかし、ルームアーチでは、パラメーターとしてtrue / falseを渡すことができませんでした。代わりtrue =1false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Vishnu TB

4
Room 2.2.0-alpha01(developer.android.com/jetpack/androidx/releases/…)には、ターゲットエンティティを設定できる@Updateの新しいパラメーターが導入されました。これにより、部分的な更新が可能になります。
ジョナス

84

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

例:

エンティティ:

@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ツアーSET endAddress =:END_ADDRESS、startAdress =:start_addressのID =:TID)int型updateTour(長いTID、文字列のEND_ADDRESS、文字列のstart_addressの);
Jurij Pitulja

1
私はあなたの解決策を意味しました:)他のユーザーが見ることができるようにそこに置いた方がいいです
Michael

おお、それは明白だと思いました。今修正されました。
Jurij Pitulja

13

とおりルーム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;
}

問題の実際のツアーエンティティとともに、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. 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オブジェクトのuserItemを取得します

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

これは生のコードです。役立つことを願っています。

ハッピーコーディング


10
あなたは本当にビューモデルでデータベースアクションをしますか??? god no plz no ...: '(モデル名を表示するだけで顔に当たるはずです
mcfly

@mcfly、ビューモデルでデータベース操作を行うのが悪いと考えられるのはなぜですか?
ダニエル

単一の責任の原則が破られているはい
mcfly
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.