这是我上一个的延续,但我终于想通了(摆脱了重复的问题)。
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"并不能保证秩序。
1条答案
按热度按时间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类。请考虑以下事项:-
添加到Customer和Invoice类的getter和setter。
Debtor_Ser_No
customer_serial硬编码。为了演示修改后的测试,即a)更新数据库中的发票delivery_status值,以及b)使用一种方法记录返回的CustomerInvoices,该方法允许通过所需的交付状态:
公共类MainActivity扩展了AppCompatActivity {
}
运行时,6组(3对)结果可输出至日志。输出为: