2

I'm using ObjectBox to save data. When I save the same data with ToMany, it only save the first one.

  • ObjectBox(version:2.0.0)
  • Android(target sdk version:27)
  • Kotlin(version:1.2.60)

Here is my code.

@Entity
data class Order(@Id var id: Long = 0,
                 val createTime: Long = 0,
                 val total: Int = 0) {

    @Backlink(to = "order")
    lateinit var details: ToMany<OrderDetail>
}

@Entity
data class OrderDetail(@Id var id: Long = 0,
                       val productName: String = "",
                       val productSpecName: String = "",
                       val productSpecPrice: Int = 0,
                       val quantity: Int = 0,
                       val subtotal: Int = 0) {

    lateinit var order: ToOne<Order>
}

The test

@Test
    fun orderDetailTest() {

        val orderBox = store.boxFor(Order::class.java)

        // 儲存兩個內容相同的資料
        val order = Order().apply {
            this.details.add(OrderDetail(productSpecName = "ABC"))
            this.details.add(OrderDetail(productSpecName = "ABC"))
        }

        val orderId = orderBox.put(order)

        val result = orderBox.get(orderId)

        assert(result.details.size == 2)
    }

The size of result.details is 1.

Can I save multiple same data with ToMany? How can I fix it?

Thanks for answer.

Hank Li
  • 23
  • 3

2 Answers2

3

Kotlin data classes provide among others a custom implementation for hashCode(). ToMany uses a HashMap to keep track of entities to add or remove. I guess you can see where this is going:

Based on the Kotlin data class implementation if two data classes have the same properties, their hash codes match. Now given this example with two identical OrderDetail data classes according to their hashCode():

val order = Order().apply {
    this.details.add(OrderDetail(productSpecName = "ABC"))
    this.details.add(OrderDetail(productSpecName = "ABC"))
}

Two entities will be added to the ToMany list. However, the internal change tracking mechanism assumes that the second entity replaces the first one, because HashMap believes they are the same. Hence only one gets added.

Making OrderDetail a regular class (remove the data keyword) drops the custom hashCode() implementation and everything works as expected.

I believe in Kotlin two data classes that share the same properties are considered to be "the same", so this behavior is kind of expected. Though I agree it is unintuitive. Not sure what we should do here.

Related GitHub Issue

Uwe - ObjectBox
  • 1,012
  • 1
  • 7
  • 11
1

You need to specify the OrderDetail id, otherwise its always 0 at default and will override the previous order detail.

val orderDetail = OrderDetail(id = 1, productSpecName = "ABC")
orderDetail.order = order
this.details.add(orderDetail)
val orderDetail2 = OrderDetail(id = 2, productSpecName = "ABC")
orderDetail2.order = order
this.details.add(orderDetail2)
Fabian
  • 960
  • 13
  • 26