android Room -嵌入式对象和带有LiveData的where子句

6jygbczu  于 2023-02-06  发布在  Android
关注(0)|答案(1)|浏览(141)

这是我上一个的延续,但我终于想通了(摆脱了重复的问题)。
Android Room Relationship duplicating information

    • 客户表**
@Entity(tableName = "customer_table")
    public class Customer {
      @ColumnInfo(name = "Customer_Serial", index = true)
      @PrimaryKey
      private int customerSerial;
    
      @ColumnInfo(name = "Customer_Sort", index = true)
      private String customerSort;

      @ColumnInfo(name = "Customer_Name")
      private String customerName;
    
      public Customer(int customerSerial, String customerName) {
        this.customerSerial = customerSerial;
        this.customerName = customerName;
        this.customerSort = String.format(Locale.ENGLISH, "%d-%d", new Date().getTime(), customerSerial);
      }
    }
    • 发票表**
@Entity(tableName = "invoice_table")
    public class Invoice {
      @ColumnInfo(name = "Invoice_Number", index = true)
      @PrimaryKey
      private int invoiceNumber;
    
      @ColumnInfo(name = "Customer_Serial")
      private int customerSerial;
    
      @ColumnInfo(name = "Invoice_Sort", index = true)
      private String invoiceSort;

      @ColumnInfo(name = "Delivery_Status")
      private int deliveryStatus;

      public Invoice(int invoiceNumber, int customerSerial) {
        this.invoiceNumber = invoiceNumber;
        this.customerSerial = customerSerial;
        this.invoiceSort = String.format(Locale.ENGLISH, "%d-%d", new Date().getTime(), invoiceNumber)
      }

      public void setDeliveryStatus(int deliveryStatus) {
        this.deliveryStatus = deliveryStatus;
      }

      public int getDeliveryStatus() { return deliveryStatus; }
    }
    • 客户发票**关系
public class CustomerInvoice {
      @Embedded public Customer customer;
      @Relation(
        parentColumn = "Customer_Serial",
        entityColumn = "Customer_Serial"
        entity = Invoice.class
      )
      public List<Invoice> invoices;
    }
    • DAO**
public abstract class InvoiceDao {
     @Transaction
     @Query("SELECT * FROM invoice_table " +
            "JOIN customer_table " +
            "ON invoice_table.Debtor_Ser_No = customer_table.Customer_Serial " +
            "WHERE invoice_table.Delivery_Status = :deliveryStatus " +
            "GROUP BY customer_table.Customer_Serial " +
            "ORDER BY customer_table.Customer_Sort, invoice_table.Invoice_Sort")
    abstract public LiveData<List<CustomerInvoices>> getCustomerInvoices(int deliveryStatus);

    abstract public void insert(Invoice... invoice);

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    abstract public void insertCustomer(Customer... customer);
   }
    • 视图模型**public实时数据集客户发票(int deliveryStatus){返回道. getCustomerInvoices();} }
    • 测试**
Invoice invoice1 = new Invoice(1234, 1);
    Invoice invoice2 = new Invoice(1235, 1);
    Invoice invoice3 = new Invoice(2468, 2);
    Invoice invoice4 = new Invoice(2469, 2);

    Customer customer1 = new Customer(1, "Customer 1");
    Customer customer2 = new Customer(2, "Customer 2");

    dao.insertCustomer(customer1);
    dao.insertCustomer(customer2);
    dao.insert(invoice1);
    dao.insert(invoice2);
    dao.insert(invoice3);
    dao.insert(invoice4);

    invoice1.setDeliveryStatus(0);
    invoice2.setDeliveryStatus(0);
    invoice3.setDeliveryStatus(0);
    invoice4.setDeliveryStatus(0);
    viewModel.getCustomerInvoices2(0).observe(getViewLifeCycleOwner(), list -> { ... });

如果我调试观察者的输出,它会正确地返回2个客户,每个客户有2张发票。
但是如果我这么做了

测试2

invoice1.setDeliveryStatus(1);
   viewModel.getCustomerInvoices2(1).observe(getViewLifeCycleOwner(), list -> { ... });

它返回1个客户和2张发票,而不是1个客户和1张发票,因为该客户的第二张发票的交货状态仍然为0。
我意识到问题出在CustomerInvoice关系中,它忽略了invoice_table本身的where子句(它仍然完美地处理了customer where子句)。
然而,我似乎就是不能把我的头缠在一起来解决它。
我有谷歌搜索了相当长的一段时间了,我知道这是因为它基本上只是做"获取客户,他们至少有一个发票与正确的交货状态",然后它是做"获取此客户的所有发票",只是几乎所有我能找到的东西都给出了基本的样本,不涉及LiveData在所有,我需要它使用LiveData。
我试图让它工作的许多尝试之一,是在视图模型本身中做了大量的跑腿工作。

    • DAO**
@Query("SELECT * FROM customer_table " +
            "JOIN invoice_table " +
            "ON customer_table.Customer_Serial = invoice_table.Debtor_Ser_No " +
            "WHERE invoice_table.Delivery_Status = :deliveryStatus " +
            "GROUP BY customer_table.Customer_Serial ORDER BY customer_table.Customer_Sort")
    abstract public Maybe<List<Customer>> getCustomersByDeliveryStatus(int deliveryStatus);

    @Query("SELECT * FROM invoice_table " +
            "WHERE invoice_table.Debtor_Ser_No = :debtorSerial " +
            "AND invoice_table.Delivery_Status = :deliveryStatus " +
            "ORDER BY invoice_table.Invoice_Sort")
    abstract public Single<List<Invoice>> getCustomerInvoicesByDeliveryStatus(int debtorSerial, int deliveryStatus);
    • 视图模型**
public LiveData<List<Map<Customer, List<Invoice>>>> getCustomerInvoices2(int deliveryStatus) {
        MutableLiveData<List<Map<Customer, List<Invoice>>>> liveCustomerInvoices = new MutableLiveData<>();

        List<Map<Customer, List<Invoice>>> listCustomerInvoices = new ArrayList<>();

        mInvoiceDao
                .getCustomersByDeliveryStatus(deliveryStatus)
                .subscribeOn(Schedulers.io())
                .subscribe(
                        (customers) -> {
                            for (Customer customer : customers) {
                                mInvoiceDao.getCustomerInvoicesByDeliveryStatus(
                                        customer.getCustomerSerial(),
                                        deliveryStatus
                                ).subscribeOn(Schedulers.io())
                                        .subscribe(
                                                (invoices) -> {
                                                    listCustomerInvoices.add(Collections.singletonMap(customer, invoices));
                                                }
                                        );
                            }
                            liveCustomerInvoices.postValue(listCustomerInvoices);
                        }, throwable -> Log.e("Error", "Error")
                );

        return liveCustomerInvoices;
    }

虽然它确实工作(在不同程度上,LiveData不会立即更新,所以有时它什么也不显示,有时它只显示1件事,直到我刷新显示),我的回收视图显示正是我需要它显示,它不维护基于'Customer_Sort'和'Invoice_Sort'的顺序,必须维护。
我也理解为什么,因为"Map"并不能保证秩序。

cu6pst1q

cu6pst1q1#

我认为第一个问题是,当你有@Embedded,然后@Relation@Embedded被认为是父母(客户)。这是房间基本上忽略(在第一)的儿童(发票)。
您似乎是从发票的Angular 考虑这一点,而Room则按照@Embedded/@Relation的指示从客户的Angular 考虑这一点。
一旦Room(理论上)获得了父对象(客户),它就会从对象的Angular 考虑这一点,并获得所有子对象(发票),而不管影响所检索的子对象的SQL(例如WHERE ORDER)如何,并构建 * 完整的对象 *(父对象的所有子对象)。
WHERE和ORDER只有在更改父对象的数量时才有效。
这基本上是一种方便的方法。
如果使用Customer(@Embedded)Invoice(@Realtion)POJO需要覆盖Rooms处理的方法,则要影响子对象(Invoices),对它们进行修剪和排序。
另一个问题是,您的测试代码更改了Invoice对象(例如invoice1.setDeliveryStatus(0);),但没有将该更改应用到数据库,因此如果您从数据库中提取,则这些更改将不会应用。
而不更改CustomerInvoice类。请考虑以下事项:-
添加到CustomerInvoice类的getter和setter。

    • 发票道**转换为:-
@Dao
public abstract class InvoiceDao {

   /*
   @Transaction
   @Query("SELECT * FROM invoice_table " +
           "JOIN customer_table " +
           "ON invoice_table.Debtor_Ser_No = customer_table.Customer_Serial " +
           "WHERE invoice_table.Delivery_Status = :deliveryStatus " +
           "GROUP BY customer_table.Customer_Serial " +
           "ORDER BY customer_table.Customer_Sort, invoice_table.Invoice_Sort")
   abstract public LiveData<List<CustomerInvoice>> getCustomerInvoices(int deliveryStatus);

    */

   @Insert(onConflict = OnConflictStrategy.IGNORE)
   abstract public void insert(Invoice... invoice);
   @Insert(onConflict = OnConflictStrategy.IGNORE)
   abstract public void insertCustomer(Customer... customer);
   @Update(onConflict = OnConflictStrategy.IGNORE)
   abstract public void updateInvoice(Invoice... invoices);

   @Query("SELECT customer_table.* " + /* Room does not use the invoice table columns, they are not needed */
           "FROM customer_table " +
           "JOIN invoice_table ON invoice_table.customer_serial = customer_table.Customer_Serial " +
           "WHERE invoice_table.Delivery_Status = :deliveryStatus " +
           "GROUP BY customer_table.Customer_Serial ORDER BY customer_table.Customer_Sort, invoice_table.Invoice_Sort")
   abstract public List<Customer> getApplicableCustomers(int deliveryStatus);
   @Query("SELECT * FROM invoice_table WHERE delivery_status=:deliveryStatus AND customer_serial=:customerSerial ORDER BY invoice_sort" )
   abstract List<Invoice> getApplicableInvoicesForCustomer(int deliveryStatus, int customerSerial);

   @Transaction /* do in a single transaction */
   @Query("") /* trick room so it applies transaction processing logic*/
   public List<CustomerInvoice> getCustomerInvoices(int deliveryStatus) {
      ArrayList<CustomerInvoice> rv = new ArrayList<>();
      for(Customer c: getApplicableCustomers(deliveryStatus)) {
         CustomerInvoice ci = new CustomerInvoice();
         ci.customer = c;
         ci.invoices = getApplicableInvoicesForCustomer(deliveryStatus,c.getCustomerSerial());
         rv.add(ci);
      }
      return rv;
   }
}
      • getCustomerInvoices**方法已注解掉
      • 更新发票**方法已添加
  • 已添加getAppliableCustomers方法
  • 类似于getCustomerInvoices,但只获取Customer字段/列,因为Room不使用发票(SQL可以相应地进行调整)。
  • 而不是Debtor_Ser_No customer_serial硬编码。
  • 添加了getAppliableInvoicesForCustomer方法(用于获取适当的发票)
      • getCustomerInvoices**方法被替换为一个具有body的方法,该方法获取Customers,如Room所做的那样,但随后获取所需的子对象(发票)。这将组合getAppliable??方法并返回CustomerInvoice对象的列表。

为了演示修改后的测试,即a)更新数据库中的发票delivery_status值,以及b)使用一种方法记录返回的CustomerInvoices,该方法允许通过所需的交付状态:

      • 注意**为简洁起见,使用mainThread。

公共类MainActivity扩展了AppCompatActivity {

TheDatabase db;
  InvoiceDao dao;
  private static final String TAG = "DBINFO";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      db = TheDatabase.getInstance(this);
      dao = db.getInvoiceDao();

      Invoice invoice1 = new Invoice(1234, 1);
      Invoice invoice2 = new Invoice(1235, 1);
      Invoice invoice3 = new Invoice(2468, 2);
      Invoice invoice4 = new Invoice(2469, 2);

      Customer customer1 = new Customer(1, "Customer 1");
      Customer customer2 = new Customer(2, "Customer 2");

      dao.insertCustomer(customer1);
      dao.insertCustomer(customer2);
      dao.insert(invoice1);
      dao.insert(invoice2);
      dao.insert(invoice3);
      dao.insert(invoice4);

      logCustomerInvoices(0,"_R1");
      logCustomerInvoices(1,"_R2");

      invoice1.setDeliveryStatus(0);
      invoice2.setDeliveryStatus(0);
      invoice3.setDeliveryStatus(0);
      invoice4.setDeliveryStatus(0);
      dao.updateInvoice(invoice1);
      dao.updateInvoice(invoice2);
      dao.updateInvoice(invoice3);
      dao.updateInvoice(invoice4);
      logCustomerInvoices(0,"_R3");
      logCustomerInvoices(1,"_R4");

      invoice1.setDeliveryStatus(1);
      invoice2.setDeliveryStatus(0);
      invoice3.setDeliveryStatus(0);
      invoice4.setDeliveryStatus(0);
      dao.updateInvoice(invoice1);
      dao.updateInvoice(invoice2);
      dao.updateInvoice(invoice3);
      dao.updateInvoice(invoice4);
      logCustomerInvoices(0,"_R5");
      logCustomerInvoices(1,"_R6");

  }

  void logCustomerInvoices(int deliveryStatus, String tagSuffix) {
      for(CustomerInvoice ci: dao.getCustomerInvoices(deliveryStatus)) {
          Log.d(TAG+tagSuffix,"Customer is " + ci.customer.getCustomerName() +
                  " Serial is " + ci.customer.getCustomerSerial() +
                  " Sort is " + ci.customer.getCustomerSort() + " There are " + ci.invoices.size() + " Invoices. They are ");
          for (Invoice i: ci.invoices) {
              Log.d(TAG+tagSuffix,"\n\tInvoice # is " + i.getInvoiceNumber() + " CustSerial is " + i.getCustomerSerial() + " DlvrStatus is " + i.getDeliveryStatus() + " Sort is " +  i.getInvoiceSort());
          }
      }
  }

}
运行时,6组(3对)结果可输出至日志。输出为:

2023-02-04 06:53:16.867 D/DBINFO_R1: Customer is Customer 1 Serial is 1 Sort is 1675453996772-1 There are 2 Invoices. They are 
2023-02-04 06:53:16.868 D/DBINFO_R1:    Invoice # is 1234 CustSerial is 1 DlvrStatus is 0 Sort is 1675453996766-1234
2023-02-04 06:53:16.868 D/DBINFO_R1:    Invoice # is 1235 CustSerial is 1 DlvrStatus is 0 Sort is 1675453996771-1235
2023-02-04 06:53:16.869 D/DBINFO_R1: Customer is Customer 2 Serial is 2 Sort is 1675453996772-2 There are 2 Invoices. They are 
2023-02-04 06:53:16.869 D/DBINFO_R1:    Invoice # is 2468 CustSerial is 2 DlvrStatus is 0 Sort is 1675453996771-2468
2023-02-04 06:53:16.869 D/DBINFO_R1:    Invoice # is 2469 CustSerial is 2 DlvrStatus is 0 Sort is 1675453996771-2469

2023-02-04 06:53:16.887 D/DBINFO_R3: Customer is Customer 1 Serial is 1 Sort is 1675453996772-1 There are 2 Invoices. They are 
2023-02-04 06:53:16.887 D/DBINFO_R3:    Invoice # is 1234 CustSerial is 1 DlvrStatus is 0 Sort is 1675453996766-1234
2023-02-04 06:53:16.887 D/DBINFO_R3:    Invoice # is 1235 CustSerial is 1 DlvrStatus is 0 Sort is 1675453996771-1235
2023-02-04 06:53:16.887 D/DBINFO_R3: Customer is Customer 2 Serial is 2 Sort is 1675453996772-2 There are 2 Invoices. They are 
2023-02-04 06:53:16.887 D/DBINFO_R3:    Invoice # is 2468 CustSerial is 2 DlvrStatus is 0 Sort is 1675453996771-2468
2023-02-04 06:53:16.887 D/DBINFO_R3:    Invoice # is 2469 CustSerial is 2 DlvrStatus is 0 Sort is 1675453996771-2469

2023-02-04 06:53:16.906 D/DBINFO_R5: Customer is Customer 1 Serial is 1 Sort is 1675453996772-1 There are 1 Invoices. They are 
2023-02-04 06:53:16.906 D/DBINFO_R5:    Invoice # is 1235 CustSerial is 1 DlvrStatus is 0 Sort is 1675453996771-1235
2023-02-04 06:53:16.906 D/DBINFO_R5: Customer is Customer 2 Serial is 2 Sort is 1675453996772-2 There are 2 Invoices. They are 
2023-02-04 06:53:16.906 D/DBINFO_R5:    Invoice # is 2468 CustSerial is 2 DlvrStatus is 0 Sort is 1675453996771-2468
2023-02-04 06:53:16.906 D/DBINFO_R5:    Invoice # is 2469 CustSerial is 2 DlvrStatus is 0 Sort is 1675453996771-2469
2023-02-04 06:53:16.911 D/DBINFO_R6: Customer is Customer 1 Serial is 1 Sort is 1675453996772-1 There are 1 Invoices. They are 
2023-02-04 06:53:16.911 D/DBINFO_R6:    Invoice # is 1234 CustSerial is 1 DlvrStatus is 1 Sort is 1675453996766-1234
  • R1(由于交货状态均为0,因此退回2个客户,每个客户有2张发票)
  • R2不返回任何内容,因为没有任何客户的发票的交付状态为1
  • 发票更新不起任何作用,因为状态已为0,因此:-
  • R3返回所有
  • R4无
  • 由于1张发票的交货状态更改为1,则
  • R5返回2个Customer,但第一个具有1张发票(如预期),另一个具有2张发票(如预期
  • R6返回1个状态为1的客户,该客户具有1张发票
  • 客户和发票相应排序。

相关问题