Zaktualizuj określone pole elementu w pokoju Android

124

W moim nowym projekcie używam biblioteki trwałości pokoju systemu Android. Chcę zaktualizować niektóre pola tabeli. Próbowałem jak w moim Dao-

// Method 1:

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

Ale kiedy próbuję zaktualizować za pomocą tej metody, aktualizuje ona każde pole jednostki, w której pasuje do wartości klucza podstawowego obiektu wycieczki. używałem@Query

// Method 2:

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

Działa, ale w moim przypadku będzie wiele zapytań, ponieważ mam wiele pól w mojej encji. Chcę wiedzieć, jak mogę zaktualizować niektóre pola (nie wszystkie), na przykład Method 1gdzie id = 1; (id to automatycznie generowany klucz podstawowy).

// Entity:

@Entity
public class Tour {
    @PrimaryKey(autoGenerate = true)
    public long id;
    private String startAddress;
    private String endAddress;
    //constructor, getter and setter
}
Rasel
źródło
Jak zaktualizować listę w tabeli. Właściwie wstawiłem listę w tabeli według TypeConverter. Ale gdy nadchodzi z aktualizacją, nie działa. Proszę zasugerować, jeśli napotkałeś jakiś taki problem.
Aman Gupta - ShOoTeR
@ AmanGupta-ShOoTeR Czy otrzymałeś jakieś rozwiązanie dla powyższego komentarza?
skygeek
Moja biblioteka Kripton Persistence Library działa podobnie do tej biblioteki Room. Jeśli chcesz zobaczyć, jak rozwiązałem ten problem za pomocą Kripton, odwiedź abubusoft.com/wp/2019/10/02/ ...
xcesco
@ AmanGupta-ShOoTeR Napotkałem tego rodzaju problemy podczas aktualizacji przy użyciu „@Query”. Następnie użyłem `` @Insert (onConflict = OnConflictStrategy.REPLACE) '', tworząc obiekt z tą samą wartością klucza podstawowego zamiast aktualizacji i zadziałało
Rasel

Odpowiedzi:

68

Chcę wiedzieć, jak mogę zaktualizować niektóre pola (nie wszystkie), takie jak metoda 1, gdzie id = 1

Użyj @Query, tak jak w metodzie 2.

w moim przypadku jest zbyt długie zapytanie, ponieważ mam wiele pól w mojej encji

Następnie miej mniejsze jednostki. Lub nie aktualizuj pól indywidualnie, ale zamiast tego wykonuj bardziej zgrubne interakcje z bazą danych.

IOW, w samym Pokoju nie ma nic, co zrobi to, czego szukasz.

CommonsWare
źródło
Czy można zaktualizować tabelę bez przekazywania parametrów? Mam na myśli zamianę wartości logicznej.
Wisznu TB
1
@VishnuTB: Jeśli możesz utworzyć instrukcję SQL, która robi to, co chcesz, powinieneś móc jej używać @Query.
CommonsWare
@CommonsWare to rozumiem. Chciałem pobrać zestaw wierszy z logiczną wartością true. ale Łuk pokoju nie pozwolił mi na przekazanie parametru prawda / fałsz. zamiast true =1,false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
Wisznu TB
4
W pokoju 2.2.0-alpha01 ( developer.android.com/jetpack/androidx/releases/ ) wprowadzono nowy parametr dla @Update, który pozwala ustawić obiekt docelowy. Powinno to umożliwić częściowe aktualizacje.
Jonas
84

Według dokumentacji aktualizacji 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);

Przykład:

Jednostka:

@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
źródło
4
Czy możesz to wyjaśnić bardziej?
Michael
1
Z podmiotem z pytania metoda DAO będzie wyglądać następująco: @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
Miałem na myśli twoje rozwiązanie :) Lepiej mieć to tam, aby inni użytkownicy mogli to zobaczyć
Michael
och, myślałem, że to oczywiste. Naprawiono teraz.
Jurij Pitulja
14

Począwszy od pokoju 2.2.0 wydanego w październiku 2019 r., Można określić jednostkę docelową dla aktualizacji. Następnie, jeśli parametr aktualizacji jest inny, pomieszczenie zaktualizuje tylko kolumny części częściowej. Przykład pytania PO pokaże to nieco jaśniej.

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

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

Zauważ, że musisz utworzyć nową część częściową o nazwie TourUpdate, wraz z prawdziwym elementem Tour w pytaniu. Teraz, gdy wywołasz update z obiektem TourUpdate, zaktualizuje on endAddress i pozostawi tę samą wartość startAddress. Działa to idealnie dla mnie w moim przypadku zastosowania metody insertOrUpdate w moim DAO, która aktualizuje bazę danych nowymi zdalnymi wartościami z API, ale pozostawia dane lokalnej aplikacji w samej tabeli.

georgiecasey
źródło
6

Możesz spróbować, ale wydajność może być trochę gorsza:

@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
źródło
2

Myślę, że nie musisz aktualizować tylko określonego pola. Po prostu zaktualizuj całe dane.

@Update zapytanie

W zasadzie jest to zadane zapytanie. Nie ma potrzeby wykonywania nowego zapytania.

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

Jedyne, co musisz wiedzieć, to „id”. Na przykład, jeśli chcesz zaktualizować tylko „tytuł”, możesz ponownie użyć „treści” i „zdjęcia” z już wstawionych danych. W prawdziwym kodzie użyj w ten sposób

val memo = Memo(id, title, content, byteArrayList)
memoViewModel.update(memo)
J.Dragon
źródło
-3

Jeśli chcesz zaktualizować informacje o użytkowniku dla określonego identyfikatora użytkownika „x”,

  1. musisz utworzyć klasę dbManager , która zainicjuje bazę danych w swoim konstruktorze i będzie działać jako pośrednik między Twoim viewModel i DAO, a także.
  2. ViewModel będzie zainicjować instancję dbManager dostępu do bazy danych. Kod powinien wyglądać następująco:

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

    Następnie zaktualizuj swój element użytkownika w ten sposób, załóżmy, że twój identyfikator użytkownika to 1122, a nazwa użytkownika to „xyz”, który należy zmienić na „zyx”.

    Uzyskaj obiekt userItem o identyfikatorze 1122 User

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

To jest surowy kod, mam nadzieję, że ci pomoże.

Miłego kodowania

Kunal Parte
źródło
10
Naprawdę wykonujesz działania związane z bazami danych w modelu widoku ??? god no plz no ...: '(po prostu zobacz nazwę modelu, która powinna uderzyć cię w twarz
mcfly
@mcfly, dlaczego wykonywanie operacji na bazie danych w modelu widoku jest uważane za złe?
Daniel
zasada odpowiedzialności pojedynczej jest złamana tak
mcfly