Aktualisieren Sie ein bestimmtes Feld einer Entität in Android Room

121

Ich verwende die Android Room Persistence Library für mein neues Projekt. Ich möchte ein Tabellenfeld aktualisieren. Ich habe versucht wie in meinem Dao-

// Method 1:

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

Wenn ich jedoch versuche, mit dieser Methode zu aktualisieren, werden alle Felder der Entität aktualisiert, in denen sie mit dem Primärschlüsselwert des Tourobjekts übereinstimmen. Ich habe benutzt@Query

// Method 2:

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

Es funktioniert, aber in meinem Fall wird es viele Abfragen geben, da ich viele Felder in meiner Entität habe. Ich möchte wissen, wie ich ein Feld (nicht alle) wie Method 1id = 1 aktualisieren kann . (id ist der automatisch generierte Primärschlüssel).

// Entity:

@Entity
public class Tour {
    @PrimaryKey(autoGenerate = true)
    public long id;
    private String startAddress;
    private String endAddress;
    //constructor, getter and setter
}
Rasel
quelle
So aktualisieren Sie eine Liste in der Tabelle. Eigentlich habe ich die Liste in Tabelle von TypeConverter eingefügt. Aber während mit dem Update kommt es nicht. Bitte schlagen Sie vor, wenn Sie auf ein solches Problem gestoßen sind.
Aman Gupta - ShoTeR
@ AmanGupta-ShOoTeR Hast du eine Lösung für den obigen Kommentar bekommen?
Skygeek
Meine Bibliothek Die Kripton Persistence Library funktioniert ziemlich ähnlich wie diese Raumbibliothek. Wenn Sie sehen möchten, wie ich dieses Problem mit Kripton löse, besuchen Sie
xcesco
@ AmanGupta-ShOoTeR Ich hatte solche Probleme beim Update mit '@Query'. Dann habe ich '@Insert (onConflict = OnConflictStrategy.REPLACE)' verwendet, indem ich ein Objekt mit demselben Primärschlüsselwert anstelle von Update erstellt habe, und es hat funktioniert
Rasel

Antworten:

67

Ich möchte wissen, wie ich ein Feld (nicht alle) wie Methode 1 mit id = 1 aktualisieren kann

Verwenden @QuerySie wie in Methode 2.

ist in meinem Fall eine zu lange Abfrage, da ich viele Felder in meiner Entität habe

Dann haben kleinere Einheiten. Oder aktualisieren Sie die Felder nicht einzeln, sondern haben Sie grobkörnigere Interaktionen mit der Datenbank.

IOW, es gibt nichts im Raum selbst, was tun könnte, was Sie suchen.

CommonsWare
quelle
Ist es möglich, die Tabelle zu aktualisieren, ohne Parameter zu übergeben? Ich meine, einen booleschen Wert zu tauschen.
Vishnu TB
1
@VishnuTB: Wenn Sie eine SQL-Anweisung erstellen können, die das tut, was Sie wollen, sollten Sie sie verwenden können @Query.
CommonsWare
@ CommonsWare hat es verstanden. Ich wollte eine Reihe von Zeilen mit einem booleschen wahren Wert abrufen. Aber Room Arch erlaubte mir nicht, true / false als Parameter zu übergeben. statt true =1,false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Vishnu TB
4
In Raum 2.2.0-alpha01 ( developer.android.com/jetpack/androidx/releases/… ) wurde ein neuer Parameter für @Update eingeführt, mit dem Sie die Zielentität festlegen können. Dies sollte teilweise Aktualisierungen ermöglichen.
Jonas
84

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

Beispiel:

Entität:

@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
quelle
4
Können Sie das näher erläutern?
Michael
1
Mit Einheit von Methode Frage DAO wird wie folgt aussehen: @Query ( "UPDATE Tour - SET endAddress =: end_address, Startadresse =: start_address WHERE id =: tid) int updateTour (long tid, String end_address, String start_address);
Jurij Pitulja
1
Ich meinte in Ihrer Lösung :) Es ist besser, es dort für andere Benutzer zu haben
Michael
Oh, ich dachte es ist offensichtlich. Jetzt behoben.
Jurij Pitulja
13

Ab Raum 2.2.0, der im Oktober 2019 veröffentlicht wurde, können Sie eine Zielentität für Aktualisierungen angeben. Wenn sich der Aktualisierungsparameter unterscheidet, aktualisiert Room nur die Teilentitätsspalten. Ein Beispiel für die OP-Frage zeigt dies etwas deutlicher.

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

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

Beachten Sie, dass Sie eine neue Teilentität namens TourUpdate zusammen mit Ihrer tatsächlichen Tour-Entität in der Frage erstellen müssen. Wenn Sie jetzt update mit einem TourUpdate-Objekt aufrufen, wird endAddress aktualisiert und der Wert für startAddress bleibt unverändert. Dies funktioniert perfekt für mich, wenn ich eine insertOrUpdate-Methode in meinem DAO verwende, die die Datenbank mit neuen Remote-Werten aus der API aktualisiert, die lokalen App-Daten jedoch in der Tabelle allein lässt.

georgiecasey
quelle
6

Sie könnten dies versuchen, aber die Leistung kann etwas schlechter sein:

@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
quelle
2

Ich denke, Sie müssen nicht nur ein bestimmtes Feld aktualisieren. Aktualisieren Sie einfach ganze Daten.

@ Update-Abfrage

Es ist im Grunde eine gegebene Abfrage. Keine Notwendigkeit, eine neue Abfrage zu machen.

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

Das einzige, was Sie wissen müssen, ist 'id'. Wenn Sie beispielsweise nur "Titel" aktualisieren möchten, können Sie "Inhalt" und "Foto" aus bereits eingefügten Daten wiederverwenden . Verwenden Sie in echtem Code Folgendes

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

Wenn Sie Benutzerinformationen für eine bestimmte Benutzer-ID "x" aktualisieren müssen,

  1. Sie müssen eine dbManager- Klasse erstellen , die die Datenbank in ihrem Konstruktor initialisiert und als Vermittler zwischen Ihrem viewModel und DAO fungiert.
  2. Das ViewModel initialisiert eine Instanz von dbManager, um auf die Datenbank zuzugreifen. Der Code sollte folgendermaßen aussehen:

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

    Aktualisieren Sie dann einfach Ihr Benutzerelement auf diese Weise. Angenommen, Ihre Benutzer-ID lautet 1122 und der Benutzername lautet "xyz", was in "zyx" geändert werden muss.

    Ruft ein userItem der ID 1122 User object ab

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

Dies ist ein Rohcode, hoffe er hilft Ihnen.

Viel Spaß beim Codieren

Kunal Parte
quelle
10
Sie führen wirklich Datenbankaktionen in einem Ansichtsmodell durch ??? god no plz no ...: '(nur Modellname anzeigen sollte dich nur ins Gesicht
treffen
@mcfly, Warum wird es als schlecht angesehen, Datenbankoperationen im Ansichtsmodell auszuführen?
Daniel
Das Prinzip der Einzelverantwortung ist ja gebrochen
mcfly