Aggiorna alcuni campi specifici di un'entità in Android Room


123

Sto usando la libreria di persistenza della stanza Android per il mio nuovo progetto. Voglio aggiornare qualche campo della tabella. Ho provato come nel mio Dao-

// Method 1:

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

Ma quando provo ad aggiornare utilizzando questo metodo, aggiorna ogni campo dell'entità in cui corrisponde al valore della chiave primaria dell'oggetto tour. ho usato@Query

// Method 2:

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

Funziona ma ci saranno molte domande nel mio caso perché ho molti campi nella mia entità. Voglio sapere come posso aggiornare alcuni campi (non tutti) come Method 1dove id = 1; (id è la chiave primaria di generazione automatica).

// Entity:

@Entity
public class Tour {
    @PrimaryKey(autoGenerate = true)
    public long id;
    private String startAddress;
    private String endAddress;
    //constructor, getter and setter
}

Come aggiornare un elenco in Table. In realtà ho inserito l'elenco nella tabella di TypeConverter. Ma mentre viene fornito con l'aggiornamento, non funziona. Per favore suggerisci, se hai riscontrato problemi come questo.
Aman Gupta - ShOoTeR

@ AmanGupta-ShOoTeR Hai trovato una soluzione per il commento sopra?
skygeek

La mia libreria Kripton Persistence Library funziona in modo abbastanza simile alla libreria di Room. Se vuoi dare un'occhiata a come risolvo
xcesco

@ AmanGupta-ShOoTeR Ho riscontrato questo tipo di problema durante l'aggiornamento utilizzando "@Query". Quindi ho usato '@Insert (onConflict = OnConflictStrategy.REPLACE)' creando un oggetto con lo stesso valore di chiave primaria invece dell'aggiornamento e ha funzionato
Rasel

Risposte:


68

Voglio sapere come posso aggiornare alcuni campi (non tutti) come il metodo 1 dove id = 1

Usa @Query, come hai fatto nel Metodo 2.

è una query troppo lunga nel mio caso perché ho molti campi nella mia entità

Quindi avere entità più piccole. Oppure non aggiornare i campi individualmente, ma avere invece interazioni più grossolane con il database.

IOW, non c'è niente nella stanza stessa che farà ciò che cerchi.


È possibile aggiornare la tabella senza passare alcun parametro? Intendo scambiare un valore booleano.
Vishnu TB il

1
@VishnuTB: Se puoi creare un'istruzione SQL che fa quello che vuoi, dovresti essere in grado di usarla con @Query.
CommonsWare

@CommonsWare capito. Volevo recuperare un insieme di righe con un valore booleano vero. ma Room arch non mi ha permesso di passare true / false come parametro. invece true =1,false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Vishnu TB

4
La stanza 2.2.0-alpha01 ( developer.android.com/jetpack/androidx/releases/… ) ha introdotto un nuovo parametro per @Update che consente di impostare l'entità di destinazione. Ciò dovrebbe rendere possibili aggiornamenti parziali.
Jonas

84

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

Esempio:

Entità:

@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
Puoi spiegarci di più?
Michael

1
Con l'entità della domanda, il metodo DAO sarà simile a questo: @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
Intendevo nella tua soluzione :) È meglio averlo lì perché gli altri utenti possano vederlo
Michael

oh, pensavo fosse ovvio. Risolto ora.
Jurij Pitulja

14

A partire dalla stanza 2.2.0 rilasciata nell'ottobre 2019, è possibile specificare un'entità di destinazione per gli aggiornamenti. Quindi, se il parametro di aggiornamento è diverso, Room aggiornerà solo le colonne dell'entità parziale. Un esempio per la domanda OP lo mostrerà un po 'più chiaramente.

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

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

Nota che devi creare una nuova entità parziale chiamata TourUpdate, insieme alla tua vera entità Tour nella domanda. Ora, quando chiami update con un oggetto TourUpdate, aggiornerà endAddress e lascerà lo stesso valore startAddress. Questo funziona perfettamente per me per il mio caso d'uso di un metodo insertOrUpdate nel mio DAO che aggiorna il DB con nuovi valori remoti dall'API ma lascia i dati dell'app locale nella tabella da soli.


6

Puoi provare questo, ma le prestazioni potrebbero essere leggermente peggiori:

@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

Penso che non sia necessario aggiornare solo alcuni campi specifici. Basta aggiornare interi dati.

@Update query

È fondamentalmente una determinata query. Non c'è bisogno di fare qualche nuova query.

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

L'unica cosa che devi sapere è "id". Ad esempio, se desideri aggiornare solo "titolo", puoi riutilizzare "contenuto" e "foto" dai dati già inseriti. In codice reale, usa in questo modo

val memo = Memo(id, title, content, byteArrayList)
memoViewModel.update(memo)

-3

Se è necessario aggiornare le informazioni utente per uno specifico ID utente "x",

  1. devi creare un dbManager classe che inizializzerà il database nel suo costruttore e fungerà da mediatore tra viewModel e DAO, e anche.
  2. Il ViewModel inizializzerà un'istanza di DBManager per accedere al database. Il codice dovrebbe essere simile a questo:

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

    Quindi aggiorna semplicemente il tuo elemento utente in questo modo, supponiamo che il tuo userId sia 1122 e userName sia "xyz" che deve essere cambiato in "zyx".

    Ottieni un oggetto utente con ID 1122 Oggetto utente

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

Questo è un codice grezzo, spero che ti aiuti.

Buona codifica


10
Esegui davvero azioni di database in un viewmodel ??? god no plz no ...: '(basta visualizzare il nome del modello dovrebbe colpirti in faccia
mcfly

@mcfly, Perché è considerato sbagliato eseguire operazioni sul database nel modello di visualizzazione?
Daniel

il principio di responsabilità unica è infranto sì
mcfly
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.