อัปเดตฟิลด์เฉพาะของเอนทิตีในห้อง Android


124

ฉันใช้ไลบรารีคงอยู่ของห้อง 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 1โดยที่ 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 แต่ในขณะที่มาพร้อมกับการอัปเดตมันไม่ทำงาน โปรดแนะนำหากคุณประสบปัญหาเช่นนี้
Aman Gupta - ShOoTeR

@ AmanGupta-ShOoTeR คุณได้รับคำตอบสำหรับความคิดเห็นด้านบนหรือไม่?
skygeek

ห้องสมุด Kripton Persistence Library ของฉันทำงานค่อนข้างคล้ายกับห้องสมุด Room หากคุณต้องการดูว่าฉันแก้ไขปัญหานี้โดยใช้ Kripton อย่างไรโปรดไปที่abubusoft.com/wp/2019/10/02/…
xcesco

@ AmanGupta-ShOoTeR ฉันประสบปัญหาดังกล่าวในการอัปเดตโดยใช้ "@Query" จากนั้นฉันใช้ '@Insert (onConflict = OnConflictStrategy.REPLACE)' โดยสร้างวัตถุที่มีค่าคีย์หลักเดียวกันแทนการอัปเดตและใช้งานได้
Rasel

คำตอบ:


68

ฉันต้องการทราบว่าฉันจะอัปเดตฟิลด์บางฟิลด์ (ไม่ใช่ทั้งหมด) เช่นวิธีที่ 1 โดยที่ id = 1 ได้อย่างไร

ใช้@Queryตามที่คุณทำในวิธีที่ 2

คำถามยาวเกินไปในกรณีของฉันเนื่องจากฉันมีหลายฟิลด์ในเอนทิตีของฉัน

จากนั้นมีเอนทิตีขนาดเล็ก หรืออย่าอัปเดตฟิลด์ทีละช่อง แต่มีการโต้ตอบกับฐานข้อมูลที่หยาบกว่าแทน

IOW ไม่มีอะไรใน Room ที่จะทำในสิ่งที่คุณต้องการ


เป็นไปได้ไหมที่จะอัปเดตตารางโดยไม่ผ่านพารามิเตอร์ใด ๆ ฉันหมายถึงการแลกเปลี่ยนค่าบูลีน
Vishnu TB

1
@VishnuTB: ถ้าคุณสามารถสร้างคำสั่ง SQL @Queryที่ไม่สิ่งที่คุณต้องการคุณควรจะสามารถที่จะใช้กับ
CommonsWare

@CommonsWare ได้เลย ฉันต้องการดึงชุดของแถวที่มีค่าจริงบูลีน แต่ Room arch ไม่อนุญาตให้ส่ง true / false เป็นพารามิเตอร์ แทนtrue =1,false=0 SELECT * FROM note_table WHERE isNoteArchived == 0
พระนารายณ์วัณโรค

4
ห้อง 2.2.0-alpha01 ( developer.android.com/jetpack/androidx/releases/… ) แนะนำพารามิเตอร์ใหม่สำหรับ @Update ซึ่งช่วยให้คุณตั้งค่าเอนทิตีเป้าหมายได้ สิ่งนี้ควรทำให้การอัปเดตบางส่วนเป็นไปได้
Jonas

86

ตาม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:

@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
คุณช่วยอธิบายเพิ่มเติมได้ไหม
Michael

1
ด้วยเอนทิตีจากคำถาม DAO method จะมีลักษณะดังนี้: @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
ฉันหมายถึงวิธีแก้ปัญหาของคุณ :) จะดีกว่าถ้ามีให้ผู้ใช้คนอื่นเห็น
Michael

โอ้ฉันคิดว่ามันชัดเจน แก้ไขแล้ว
Jurij Pitulja

14

ห้อง 2.2.0 ที่เผยแพร่ในเดือนตุลาคม 2019 คุณสามารถระบุ Target Entity สำหรับการอัปเดตได้ จากนั้นหากพารามิเตอร์การอัปเดตแตกต่างกันห้องจะอัปเดตคอลัมน์เอนทิตีบางส่วนเท่านั้น ตัวอย่างสำหรับคำถาม 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 พร้อมกับเอนทิตี Tour จริงของคุณในคำถาม ตอนนี้เมื่อคุณเรียกการอัปเดตด้วยออบเจ็กต์ TourUpdate มันจะอัปเดต endAddress และปล่อยให้ค่า startAddress เหมือนเดิม สิ่งนี้เหมาะสำหรับฉันสำหรับการใช้งานของฉันในกรณีของเมธอด insertOrUpdate ใน DAO ของฉันที่อัปเดต DB ด้วยค่ารีโมตใหม่จาก API แต่ปล่อยข้อมูลแอปในเครื่องไว้ในตารางเพียงอย่างเดียว


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. คุณต้องสร้างคลาสdbManagerที่จะเริ่มต้นฐานข้อมูลในตัวสร้างและทำหน้าที่เป็นสื่อกลางระหว่าง viewModel และ DAO ของคุณและยัง
  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"

    รับ userItem ของ id 1122 User object

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

นี่เป็นรหัสดิบหวังว่าจะช่วยคุณได้

มีความสุขในการเขียนโค้ด


10
คุณทำฐานข้อมูลจริงๆใน viewmodel ??? god no plz no ... : '(แค่ดูชื่อรุ่นก็น่าจะโดนหน้าคุณ
mcfly

@mcfly เหตุใดการดำเนินการฐานข้อมูลใน View Model จึงถือว่าไม่ดี
Daniel

หลักการความรับผิดชอบเดียวเสียใช่
mcfly
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.