Kotlin Exposed一对多关联配置问题:关联数据获取返回null
Order与OrderProductAmount一对多关联返回null问题修复
问题描述
需要在Order实体与OrderProductAmount实体间构建一对多关联,用于记录每个Order包含的Product及其amount(一个订单可包含多个商品)。但从数据库获取Order实体后,访问order.products时返回null,怀疑是实体配置或数据插入方式有误。
相关代码
Order Entity
class Order(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<Order>(Orders) var orderStatus by Orders.orderStatus val products by OrderProductAmount referrersOn OrderProductAmounts.order } object Orders : IntIdTable() { var orderStatus = enumeration("orderStatus", OrderStatus::class) }
OrderProductAmount Entity
class OrderProductAmount(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<OrderProductAmount>(OrderProductAmounts) var order by Order referencedOn OrderProductAmounts.order var product by OrderProductAmounts.product var amount by OrderProductAmounts.amount } object OrderProductAmounts : IntIdTable() { var order = reference("order", Orders) var product = integer("product") var amount = integer("amount") }
Product Entity
class Product(id: EntityID<Int>) : IntEntity(id) { companion object : IntEntityClass<Product>(Products) var name by Products.name var price by Products.price } object Products : IntIdTable() { val name = varchar("name", length = 256) val price = decimal("price", precision = 10, scale = 2) }
插入新实体代码
override suspend fun addOrder(productIdToAmount: Map<Int, Int>) = dbQuery { val orderId = Orders.insertAndGetId { it[Orders.orderStatus] = OrderStatus.CREATED } productIdToAmount.entries.forEach { (productId, amount) -> val product = productDAO.findProduct(productId)!! OrderProductAmounts.insert { it[OrderProductAmounts.order] = orderId.value it[OrderProductAmounts.product] = product.id.value it[OrderProductAmounts.amount] = amount } } }
查询订单代码
override suspend fun findOrder(id: Int): Order? = dbQuery { Orders.select { Orders.id eq id }.map { Order.wrapRow(it) }.singleOrNull() }
问题分析与修复方案
1. 插入数据时外键类型不匹配
插入OrderProductAmounts时,order字段应传入EntityID<Int>类型的orderId,而非其对应的Int值。虽然Exposed支持自动转换,但直接使用EntityID能确保关联关系的正确性,避免潜在的类型映射问题。
修改后的插入代码:
override suspend fun addOrder(productIdToAmount: Map<Int, Int>) = dbQuery { val orderId = Orders.insertAndGetId { it[orderStatus] = OrderStatus.CREATED } productIdToAmount.entries.forEach { (productId, amount) -> val product = productDAO.findProduct(productId)!! OrderProductAmounts.insert { it[order] = orderId // 直接传入EntityID it[product] = product.id.value it[amount] = amount } } }
2. 查询方式未正确初始化关联属性
手动使用select+wrapRow创建Order实体时,无法正确初始化关联的products属性。改用Exposed提供的findById方法,它会自动处理实体关联上下文,确保关联属性能正常加载。
修改后的查询代码:
override suspend fun findOrder(id: Int): Order? = dbQuery { Order.findById(id) }
3. 验证关联配置与数据库数据
- 确认
Order实体中的products定义:val products by OrderProductAmount referrersOn OrderProductAmounts.order,该配置正确,与OrderProductAmount中的order关联形成一对多关系。 - 检查数据库
order_product_amount表,确认对应订单的关联记录存在,且外键order的值与订单ID一致。若数据库无关联数据,products会返回空集合而非null;若仍返回null,说明实体初始化异常,使用findById即可解决。
内容的提问来源于stack exchange,提问作者tonik
相关产品推荐
相关产品推荐

