在房间数据库 Android 中返回带有嵌套关系的空数据
Posted
技术标签:
【中文标题】在房间数据库 Android 中返回带有嵌套关系的空数据【英文标题】:Null Data Returned with Nested Relation in Room Database Android 【发布时间】:2021-11-02 19:03:22 【问题描述】:鉴于我有 3 个实体,Order
包含 LineItem
的列表,每个 LineItem 将通过 productId 与一个 Product
关联。
从OrderDao获取数据时,product
字段返回null,但lineItem
字段有数据的问题。虽然我可以使用 ProductWithLineItem 数据。
已经尝试了很多解决方法,但它不起作用。
这是我的实体和 dao 代码
实体
@Entity(tableName = DataConstant.ORDER_TABLE)
data class Order(
@PrimaryKey
@ColumnInfo(name = "orderId")
val id: String,
@ColumnInfo(name = "status")
var status: String
)
@Entity(tableName = DataConstant.LINE_ITEM_TABLE)
data class LineItem(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "lineItemId")
val id: Long,
@ColumnInfo(name = "productId")
val productId: String,
@ColumnInfo(name = "orderId")
val orderId: String,
@ColumnInfo(name = "quantity")
var quantity: Int,
@ColumnInfo(name = "subtotal")
var subtotal: Double
)
@Entity(tableName = DataConstant.PRODUCT_TABLE)
data class Product(
@PrimaryKey
@NonNull
@ColumnInfo(name = "productId")
val id: String,
@ColumnInfo(name = "name")
var name: String?,
@ColumnInfo(name = "description")
var description: String?,
@ColumnInfo(name = "price")
var price: Double?,
@ColumnInfo(name = "image")
var image: String?,
)
关系 POJO
data class ProductAndLineItem(
@Embedded val lineItem: LineItem?,
@Relation(
parentColumn = "productId",
entityColumn = "productId"
)
val product: Product?
)
data class OrderWithLineItems(
@Embedded var order: Order,
@Relation(
parentColumn = "orderId",
entityColumn = "orderId",
entity = LineItem::class
)
val lineItemList: List<ProductAndLineItem>
)
道
@Dao
interface OrderDao
@Transaction
@Query("SELECT * FROM `$DataConstant.ORDER_TABLE` WHERE orderId = :id")
fun getById(id: String): Flow<OrderWithLineItems>
Dao运行后的结果
Result after running query
【问题讨论】:
【参考方案1】:这是我的实体和 dao 代码
你的代码看起来很好,除了返回一个流,测试,使用你的代码,但是在主线程上使用 List(并且没有 WHERE 子句),即 Dao 是:-
@Query("SELECT * FROM $DataConstant.ORDER_TABLE")
@Transaction
abstract fun getOrderWithLineItemsAndWithProduct(): List<OrderWithLineItems>
结果:-
正在加载/测试的数据使用:-
db = TheDatabase.getInstance(this)
orderDao = db.getOrderDao()
orderDao.clearAll()
orderDao.insert(Product("product1","P1","desc1",10.01,"image1"))
orderDao.insert(Product("product2","P2","desc2",10.02,"image2"))
orderDao.insert(Product("product3","P3","desc3",10.03,"image3"))
orderDao.insert(Product("product4","P4","desc4",10.04,"image4"))
orderDao.insert(Product("","","",0.0,""))
val o1 = orderDao.insert(Order("Order1","initiaited"))
val o2 = orderDao.insert(Order("Order2","finalised")) // Empty aka no List Items
val o1l1 = orderDao.insert(LineItem(10,"product3","Order1",1,10.01))
val o1l2 = orderDao.insert(LineItem(20,"product4","Order1",2,20.08))
val o1l3 = orderDao.insert(LineItem(30,"","Order1",3,30.09))
val o1l4 = orderDao.insert(LineItem(40,"","x",1,10.01))
//val o1l3 = orderDao.insert(LineItem(30,"no such product id","Order1",10,0.0))
// exception whilst trying to extract if not commented out at test = ....
val TAG = "ORDERINFO"
val test = orderDao.getOrderWithLineItemsAndWithProduct()
for(owl: OrderWithLineItems in orderDao.getOrderWithLineItemsAndWithProduct())
Log.d(TAG,"Order is $owl.order.id status is $owl.order.status")
for(pal: ProductAndLineItem in owl.lineItemList)
Log.d(TAG,"\tLine Item is $pal.lineItem.id " +
"for Order $pal.lineItem.orderId " +
"for ProductID $pal.lineItem.productId " +
"Quantity=$pal.lineItem.quantity " +
"Product description is $pal.product.description Product Image is $pal.product.image Price is $pal.product.price")
因此,我认为问题可能是由于某种原因,Flow 正在检测第一个查询何时完成但在基础查询之前。
也就是说,当使用@Relation 时,核心对象(订单)通过查询提取并创建核心对象,然后相关对象由另一个查询提取并用于将所有相关对象构建为列表(除非只是一个当它不必是一个列表时)。因此,在此基础查询之前,核心对象将具有基础对象的 null 或空列表。当然,对于@Relations 的层次结构,它会沿着/向下复制层次结构。
我建议暂时将.allowMainThreadQueires
添加到databaseBuilder 并使用List<OrderWithLineItems>
或仅使用一个OrderWithLineItems
。如果使用它,那么您将获得产品,那么问题在于流程(这是我怀疑的)。
【讨论】:
尚未尝试过,但感谢@MikeT 对此案例的深入解释。关于性能,在主线程上查询可能不好,这种情况有什么优化的方法吗? 已经解决了这个问题。问题是因为我在编写测试时忘记插入产品数据。 Flow 运行良好,没有问题。再次感谢@MikeT 的回答以上是关于在房间数据库 Android 中返回带有嵌套关系的空数据的主要内容,如果未能解决你的问题,请参考以下文章
带有 RxJava Single 的 Android Livedata 在房间数据库中不起作用