带有LiveData的房间:适配器中的多对多映射

问题描述 投票:0回答:1

让我们举个例子:

产品和订单存在多对多的映射。因此,产品可以是多个订单,订单可以有多个产品。在房间我有一个实体,它同时具有产品ID和订单ID作为外键,所以我可以保存关系。现在很容易获得特定产品的所有订单以及特定订单的所有产品。

现在来麻烦了。据我所知,没有办法在1个查询/实体中获取所有产品的订单对象。这可以更详细地阅读in this post.在大多数地方,我可以通过运行两个查询来绕过这个。第一个获得我感兴趣的订单,第二个获得基于订单ID的产品。

现在我想在适配器中显示订单与其产品的组合。为此,我需要将我的所有订单与他们的产品结合起来。我对如何用LiveData解决这个问题一无所知。

我认为最好的解决方案是创建一个直接从数据库中获取OrderWithProducts的查询。 This post suggests它应该是可能的,但我没有设法使这个工作。此示例中最重要的部分也是缺失的:OrderItem类。

如果该解决方案不可行,必须有一些方法来获取具有2个查询的LiveData OrderWithProducts列表,并以某种方式组合它们。

编辑在@Demigod的建议之后我现在在我的ViewModel中有以下内容:

// MediatorLiveData can observe other LiveData objects and react on their emissions.
var liveGroupWithLights = MutableLiveData<List<GroupWithLights>>()

fun createOrdersWithProducts() {
        appExecutors.diskIO().execute {
            val ordersWithProducts = mutableListOf<OrderWithProducts>()
            val orders = orderRepository.getGroupsSync()
            for (order in orders) {
                val products = productRepository.getProductsSync(order.id)
                val orderWithProducts = OrderWithProducts(order, products)
                ordersWithProducts.add(orderWithProducts)
            }

            liveGroupWithLights.postValue(ordersWithProducts)
        }
    }

我的片段中的函数将数据提交给适配器:

private fun initRecyclerView() {
    orderListViewModel.getOrdersWithProducts().observe(this, Observer { result ->
        adapter.submitList(result)
    })
}

所以现在我可以将OrderWithProduct对象作为我的适配器的项目。这很棒,我可以为我的适配器中的每个订单使用产品。现在,只要数据库中的值发生更改,我就无法更新这些项目。这部分的任何想法?

Edit2:invalidationtracker

db.invalidationTracker.addObserver(object : InvalidationTracker.Observer("orders", "products", "order_product_join") {
        override fun onInvalidated(tables: MutableSet<String>) {
            createOrdersWithProducts()
        }
    })

我现在遇到的问题是验证跟踪器会因一次更改而得​​到很多通知。

android kotlin android-room android-livedata
1个回答
0
投票

据我所知,目前单一查询不可能。要解决此问题,您需要在此处运行多个查询。首先 - 使用单个查询获取订单列表,然后获取每个订单的产品列表。为实现这一目标,我可以考虑几种选择:

  1. 制作你自己的OrdersWithProductsProvider,它将返回这个组合实体(OrderList<Porduct>),并且它将订阅database的更改,以便在每个LiveDataorders表更改时使用products发出新对象。
  2. 您可以使用MediatorLiveDataOrders填充Products列表,但我不认为这是最好的方法,因为您需要在后台线程中运行查询,也许在这里使用Rx更方便。

就个人而言,我会使用第一个选项,因为我可能希望获得最新的订单列表及其产品,这意味着更新应触发更改三个表(productsordersproducts_to_orders),这可能是通过Room.InvalidationTracker完成。在提供者内部,我会使用Rx(可以通过LiveDataLiveDataReactiveStreams一起使用)。

除了如何实现这一点:

如何实现这一点并不重要,唯一的事情 - 在后台线程中运行整个查询将其发布到LiveData。你可以使用ExecutorRx或简单的Thread。所以它看起来像:

private val database : Database // Get the DB
private val executor = Executors.newSingleThreadExecutor()
private val liveData = MutableLiveData<List<OrderWithProducts>>()

fun observeOrdersWithProducts():LiveData<List<OrderWithProducts>> {
    return liveData
}

private fun updateOrdersWithProducts() {
    executor.post {
        val ordersWithProducts = mutableListOf<OrderWithProducts>()
        val orders = db.orders()
        for (order : orders) {
            val products = database.productsForOrder(order)
            val orderWithProducts = OrderWithProducts(order, products)
            ordersWithProducts.add(orderWithProducts)
        }
        liveData.post(ordersWithProducts)
    }
}

将其视为不完整的工作代码,而不是实现的示例。在初始化/第一次调用时调用updateOrdersWithProducts,每次InvalidationTracker都会通知db更改。

© www.soinside.com 2019 - 2024. All rights reserved.