android - 通过房间数据库的一对多关系出现问题

标签 android sql sqlite kotlin android-room

我正在寻找一种使用 room 创建一对多关系的方法。问题是要获取具体数据。我在官方文档中找到了推荐的方法。

客户.class

@Entity(tableName = "customers")
data class Customer(
        val name: String
) {
    @PrimaryKey(autoGenerate = true) val id: Long = 0
}

订单.class

@Entity(tableName = "orders")
data class Order(
        val customerId: Long,
        val date: Long,
        val description: String
) {
    @PrimaryKey(autoGenerate = true) val id: Long = 0
}

CustomerWithOrders.class

class CustomerWithOrders() {

    @Embedded
    lateinit var customer: Customer

    @Relation(parentColumn = "id", entityColumn = "customerId", entity = Order::class)
    var orders: List<Order> = arrayListOf()
}

Dao.接口(interface)

@Transaction
    @Query("SELECT * FROM customers")
    fun getCustomersWithOrders(): LiveData<List<CustomerWithOrders>>

但是官方文档没有说明如何在保持一对多关系的同时发出有条件的请求。 我编写了一个示例查询,但它提供了不正确的数据。

查询数据不正确。

@Transaction
    @Query("SELECT * FROM customers LEFT JOIN orders ON orders.customerId=customers.id WHERE date BETWEEN :dateStart AND :dateEnd")
    fun getCustomersWithOrdersByDate(dateStart: Calendar, dateEnd: Calendar): LiveData<List<CustomerWithOrders>>

请告诉我如何正确完成我的查询或告诉来源正在执行类似的操作。而且无论如何。谢谢。

最佳答案

您可以使用以下内容作为基础(java 而不是 kotlin):-

CustomerWithOrders.java

public class CustomerWithOrders {

    Customer customer;
    List<Order> orders;

    //<<<<<<<<<<< this constructor >>>>>>>>>>
    public CustomerWithOrders(Customer customer, List<Order> orders) {
        this.customer = customer;
        this.orders = orders;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public List<Order> getOrders() {
        return orders;
    }

    public void setOrders(List<Order> orders) {
        this.orders = orders;
    }
}

结合(在 WHERE 子句中添加日期)(在 PersonDao.java 中)

@Query("SELECT * FROM Orders WHERE customerId=:customerId")
abstract List<Order> getCustomerOrders(long customerId);

然后使用类似:-

    List<Customer> allCustomers = mPDB.personDao().getAllCustomers(); //<<<<<<<< Get the required Customers (all in this example)
    ArrayList<CustomerWithOrders> allCWO = new ArrayList<>(); //<<<<<<<<<< Empty CustomerWithOrders array
    for (Customer c: allCustomers) {
        allCWO.add(new CustomerWithOrders(c,mPDB.personDao().getCustomerOrders(c.getId()))); //<<<<<<<< tie the orders to the customer
    }
    //<<<<<<<<< for demo >>>>>>>>>>
    String TAG = "CWOINFO";
    StringBuilder sb = new StringBuilder();
    for (CustomerWithOrders cwo: allCWO ) {
        sb.append("\nCustomer is " + cwo.getCustomer().getName());
        for (Order o: cwo.getOrders()) {
            sb.append("\n\tOrder is " + o.getDescription());
        }
    }
    Log.d(TAG,sb.toString());

结果(列出所有订单以供检查):-

2019-06-29 18:27:49.368 D/ORDERINFO: OrderID = 1Description = Order1 for Customer1Cust ID = 1
2019-06-29 18:27:49.368 D/ORDERINFO: OrderID = 2Description = Order2 for Customer1Cust ID = 1
2019-06-29 18:27:49.368 D/ORDERINFO: OrderID = 3Description = Order3 for Customer1Cust ID = 1
2019-06-29 18:27:49.368 D/ORDERINFO: OrderID = 4Description = Order1 for Customer2Cust ID = 2
2019-06-29 18:27:49.368 D/ORDERINFO: OrderID = 5Description = Order2 for Customer2Cust ID = 2
2019-06-29 18:27:49.368 D/ORDERINFO: OrderID = 6Description = Order3 for Customer2Cust ID = 2
2019-06-29 18:27:49.368 D/ORDERINFO: OrderID = 7Description = Order4 for Customer2Cust ID = 2
2019-06-29 18:27:49.368 D/ORDERINFO: OrderID = 8Description = Order1 for Customer3Cust ID = 3


<<<<<<<<<< The output from the above code >>>>>>>>>>
2019-06-29 18:27:49.377 D/CWOINFO: Customer is Customer1
        Order is Order1 for Customer1
        Order is Order2 for Customer1
        Order is Order3 for Customer1
    Customer is Customer2
        Order is Order1 for Customer2
        Order is Order2 for Customer2
        Order is Order3 for Customer2
        Order is Order4 for Customer2
    Customer is Customer3
        Order is Order1 for Customer3

替代方案

通过将以下方法添加到CustomerWithOrders.java

    public void addOrder(Order newOrder) {
        this.orders.add(newOrder);
    }

并将以下内容添加到 Dao 中:-

@Query("SELECT * FROM customers WHERE id=:customerId")
abstract Customer getCustomerById(long customerId);

@Query("SELECT * FROM orders LEFT JOIN customers ON orders.customerId = customers.id WHERE date BETWEEN :dateStart AND :dateEnd ORDER BY customerId")
abstract List<Order> getOrders(long dateStart, long dateEnd); 

@Transaction
public List<CustomerWithOrders> getCustomersWithOrdersInDateRange(long dateStart, long dateEnd) {
    List<Order> ordersWithCustomer = getOrders(dateStart,dateEnd);
    ArrayList<CustomerWithOrders> cwo = new ArrayList<>();
    long currentCustomerId = 0;
    for (Order o: ordersWithCustomer) {
        if (o.getCustomerId() != currentCustomerId) {
            currentCustomerId = o.getCustomerId();
            cwo.add(new CustomerWithOrders(getCustomerById(o.getCustomerId()),new ArrayList<Order>()));
        }
        cwo.get(cwo.size()-1).addOrder(o);
    }
    return cwo;
}

您可以使用以下代码:-

List<CustomerWithOrders> selectedCustomersWithOrders = mPDB.customerOrderDao().getCustomersWithOrdersInDateRange(0,99999999999999999L);

使用 LiveData(部分示例)

注意尚未完全测试,因为我通常使用 allowMainThreadQueries() 来获取答案

@Query("SELECT * FROM orders LEFT JOIN customers ON orders.customerId = customers.id WHERE date BETWEEN :dateStart AND :dateEnd ORDER BY customerId")
abstract LiveData<List<Order>> getOrders(long dateStart, long dateEnd); //<<<<<<<<<<< LD

@Transaction
public List<CustomerWithOrders> getCustomersWithOrdersInDateRange(long dateStart, long dateEnd) {
    LiveData<List<Order>> ordersWithCustomer = getOrders(dateStart,dateEnd); //<<<<<<<<<<< LD
    ArrayList<CustomerWithOrders> cwo = new ArrayList<>();
    long currentCustomerId = 0;
    for (Order o: ordersWithCustomer.getValue()) { //<<<<<<<<<<< LD
        if (o.getCustomerId() != currentCustomerId) {
            currentCustomerId = o.getCustomerId();
            cwo.add(new CustomerWithOrders(getCustomerById(o.getCustomerId()),new ArrayList<Order>()));
        }
        cwo.get(cwo.size()-1).addOrder(o);
    }
    return cwo;
}
  • 评论表示更改

关于android - 通过房间数据库的一对多关系出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56815527/

相关文章:

android - 为什么android看不到这个内部类?

android - 如何在 Android 后台播放 YouTube 视频?

android - Google Firebase FirebaseMessaging.onMessage.listen 在 flutter 中多次调用

php - 使用 PHP 和 MySQL 通过 current_timestamp 生成站点地图

SQL/Oracle 10g - 触发器问题

android - 如何更新 Android SQLITE 中除 Unique Constraint 属性外的所有行属性?

Android CheckedTextView 如何获取 choiceIndicator 默认可绘制名称?

mysql - SQL在具有多个条件的选择中对行进行排序

php - 成功登录后如何将用户重定向到新的 PHP 页面?

sqlite - 检查 SQlite 中文本的编码