Mettre à jour un champ spécifique d'une entité dans Android Room

123

J'utilise la bibliothèque de persistance de salle Android pour mon nouveau projet. Je veux mettre à jour un champ de table. J'ai essayé comme dans mon Dao-

// Method 1:

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

Mais lorsque j'essaie de mettre à jour à l'aide de cette méthode, il met à jour chaque champ de l'entité où il correspond à la valeur de clé primaire de l'objet de tournée. j'ai utilisé@Query

// Method 2:

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

Cela fonctionne mais il y aura de nombreuses requêtes dans mon cas car j'ai de nombreux champs dans mon entité. Je veux savoir comment puis-je mettre à jour certains champs (pas tous) comme Method 1where id = 1; (id est la clé primaire de génération automatique).

// Entity:

@Entity
public class Tour {
    @PrimaryKey(autoGenerate = true)
    public long id;
    private String startAddress;
    private String endAddress;
    //constructor, getter and setter
}
Rasel
la source
Comment mettre à jour une liste dans Table. En fait, j'ai inséré la liste dans Table by TypeConverter. Mais en venant avec la mise à jour, cela ne fonctionne pas. S'il vous plaît suggérer, si vous avez rencontré un problème comme celui-ci.
Aman Gupta - ShOoTeR
@ AmanGupta-ShOoTeR Avez-vous trouvé une solution pour le commentaire ci-dessus?
skygeek
Ma bibliothèque Kripton Persistence Library fonctionne de manière assez similaire à cette bibliothèque Room. Si vous voulez voir comment je résous ce problème en utilisant Kripton, veuillez visiter abubusoft.com/wp/2019/10/02/…
xcesco
@ AmanGupta-ShOoTeR J'ai rencontré ce genre de problèmes lors de la mise à jour en utilisant «@Query». Ensuite, j'ai utilisé '@Insert (onConflict = OnConflictStrategy.REPLACE)' en créant un objet avec la même valeur de clé primaire au lieu de mettre à jour et cela a fonctionné
Rasel

Réponses:

68

Je veux savoir comment puis-je mettre à jour certains champs (pas tous) comme la méthode 1 où id = 1

Utilisez @Query, comme vous l'avez fait dans la méthode 2.

est une requête trop longue dans mon cas car j'ai plusieurs champs dans mon entité

Ensuite, ayez des entités plus petites. Ou, ne mettez pas à jour les champs individuellement, mais ayez plutôt des interactions plus grossières avec la base de données.

IOW, il n'y a rien dans la salle elle-même qui fera ce que vous cherchez.

CommonsWare
la source
Est-il possible de mettre à jour la table sans passer de paramètres? Je veux dire échanger une valeur booléenne.
Vishnu TB
1
@VishnuTB: Si vous pouvez créer une instruction SQL qui fait ce que vous voulez, vous devriez pouvoir l'utiliser avec @Query.
CommonsWare
@CommonsWare l'a compris. Je voulais récupérer un ensemble de lignes avec une valeur booléenne vraie. mais l'arc de la pièce ne m'a pas permis de passer vrai / faux comme paramètre. à la place true =1,false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Vishnu TB
4
La salle 2.2.0-alpha01 ( developer.android.com/jetpack/androidx/releases/… ) a introduit un nouveau paramètre pour @Update qui vous permet de définir l'entité cible. Cela devrait permettre des mises à jour partielles.
Jonas
84

Selon la documentation de mise à jour 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);

Exemple:

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);
}
Jurij Pitulja
la source
4
Pouvez-vous expliquer cela davantage?
Michael
1
Avec l'entité de la question, la méthode DAO ressemblera à ceci: @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
Je voulais dire dans votre solution :) Il est préférable de l'avoir là pour que les autres utilisateurs puissent le voir
Michael
oh, je pensais que c'était évident. Corrigé maintenant.
Jurij Pitulja
14

À partir de la salle 2.2.0 publiée en octobre 2019, vous pouvez spécifier une entité cible pour les mises à jour. Ensuite, si le paramètre de mise à jour est différent, Room ne mettra à jour que les colonnes d'entité partielle. Un exemple pour la question OP le montrera un peu plus clairement.

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

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

Notez que vous devez créer une nouvelle entité partielle appelée TourUpdate, avec votre véritable entité Tour dans la question. Désormais, lorsque vous appelez update avec un objet TourUpdate, il met à jour endAddress et laisse la valeur startAddress identique. Cela fonctionne parfaitement pour moi pour mon cas d'utilisation d'une méthode insertOrUpdate dans mon DAO qui met à jour la base de données avec de nouvelles valeurs distantes de l'API mais laisse les données de l'application locale dans la table seules.

Georgiecasey
la source
6

Vous pouvez essayer ceci, mais les performances peuvent être un peu moins bonnes:

@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
la source
2

Je pense que vous n'avez pas besoin de mettre à jour uniquement un champ spécifique. Mettez simplement à jour toutes les données.

Requête @Update

Il s'agit essentiellement d'une requête donnée. Pas besoin de faire une nouvelle requête.

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

La seule chose que vous devez savoir est «id». Par exemple, si vous souhaitez mettre à jour uniquement le «titre», vous pouvez réutiliser le «contenu» et la «photo» à partir de données déjà insérées. Dans du vrai code, utilisez comme ça

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

Si vous devez mettre à jour les informations utilisateur pour un ID utilisateur spécifique «x»,

  1. vous devez créer une classe dbManager qui initialisera la base de données dans son constructeur et agit comme un médiateur entre votre viewModel et DAO, ainsi que.
  2. Le ViewModel initialisera une instance de dbManager pour accéder à la base de données. Le code devrait ressembler à ceci:

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

    Ensuite, mettez simplement à jour votre élément utilisateur de cette façon, supposons que votre userId soit 1122 et que userName soit "xyz" qui doit être changé en "zyx".

    Obtenir un objet userItem de l'id 1122 User object

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

Ceci est un code brut, j'espère qu'il vous aidera.

Bon codage

Kunal Parte
la source
10
Vous faites vraiment de l'action de bases de données dans un viewmodel ??? god no plz no ...: '(il suffit de voir le nom du modèle devrait juste vous frapper au visage
mcfly
@mcfly, Pourquoi est-il considéré comme inapproprié d'effectuer des opérations de base de données dans le modèle de vue?
Daniel le
le principe de responsabilité unique est rompu oui
mcfly