Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entities in Backlink ToMany reappearing after removing #1065

Open
tom-sosedow opened this issue Mar 30, 2022 · 1 comment
Open

Entities in Backlink ToMany reappearing after removing #1065

tom-sosedow opened this issue Mar 30, 2022 · 1 comment
Labels
bug Something isn't working

Comments

@tom-sosedow
Copy link

Describe the bug
When trying to remove entities from a One-To-Many relationship, they keep reappearing in the database after put() when first removing from the relationship and afterwards from box

Basic info (please complete the following information):

  • ObjectBox version: 3.1.0
  • Reproducibility: always
  • Device: Galaxy S10 (Android 11), OnePlus 6T (Android 11), Pixel 4 (Android 12)
  • OS: Android 11 and 12

To Reproduce
Steps to reproduce the behavior:

  1. Create 2 entities with a 1:N relationship (one and many)
  2. Add some entities to the ToMany (many) of the other (one).
  3. Remove 1 entity from the relationship with one.many.removeById(id)
  4. Remove the entity from the box box.remove(id)
  5. Put the parent (one) in the box again (overriding it)

Expected behavior
No matter the order, if an entity gets deleted from the box and the relation and is nowhere to be found, it should not reappear in the box.

Code
My Repo
Example code where I tested the issue in a Kotlin project

fun main(args: Array<String>) {
    val store: BoxStore = MyObjectBox.builder().name("objectbox-notes-db").build()
    val imageBox = store.boxFor<Image>().also { it.removeAll() }
    val propertyBox = store.boxFor<Property>().also { it.removeAll() }
    val originalImage = Image()
    imageBox.put(originalImage)
    originalImage.apply {
        properties.addAll(listOf(
            Property(name = "h1"),
            Property(name = "h2"),
            Property(name = "h3")
        ))
    }
    imageBox.put(originalImage)
    println("Boxed Properties: " + propertyBox.all.map { it.id })
    println("Original Image Properties: " + originalImage.properties.map { it.id })
    val removedID = propertyBox.all.first().id
    println("Removing id ${removedID}")
    val image = imageBox.get(originalImage.id).also {
        it.properties.removeById(removedID) //changing the order of these 2 will make 
        propertyBox.remove(propertyBox.all.first().id) // it work as expected
        it.properties.applyChangesToDb()
    }
    println("--------------")
    println("Both houldn't have ${removedID}: ")
    println("Boxed Properties before put: " + propertyBox.all.map { it.id })
    println("New Image Properties before put: " + image.properties.map { it.id })

    imageBox.put(image)

    println("--------------")
    println("Should still not have ${removedID}")
    println("Boxed Properties after put: " + propertyBox.all.map { it.id })
    println("New Image Properties after put: " + image.properties.map { it.id })
    }

@Entity
data class Image(
    @Id
    var id: Long = 0,
   ....
) {
    @Backlink(to = "image")
    lateinit var properties: ToMany<Property>
}

@Entity
data class Property(
    @Id
    var id: Long = 0,
   ..
) {
    lateinit var image: ToOne<Image>
}

Additional context
Flipping the order (e.g. first removing the entity from the box) and THEN removing it from the ToMany works.

@tom-sosedow tom-sosedow added the bug Something isn't working label Mar 30, 2022
@greenrobot-team
Copy link
Member

greenrobot-team commented Apr 4, 2022

Thanks for reporting! The issue are these lines as you already found out:

it.properties.removeById(removedID)
propertyBox.remove(removedID)
it.properties.applyChangesToDb()

It should be done in this order:

it.properties.removeById(removedID)
it.properties.applyChangesToDb() // Update the relation first.
propertyBox.remove(removedID) // Then remove any objects.

The ToMany properties is not an actual relation, but based on the ToOne image (@Backlink). Therefore applyChangesToDb() has to modify the ToOne of a related Property to add or remove it from the relation.
It does this by setting the ToOne target, in case of removal to null, and then putting the Property.
If the Property to be updated was removed from its box in the meantime, it will not be updated, but (re-)inserted instead.

We'll see if this can be improved by explicitly requiring an update which would do nothing if the object was already removed from its box.

Side-note: you may want to have a look at ToMany.setRemoveFromTargetBox(true) which also removes related objects when they are removed from the relation.

@greenrobot-team greenrobot-team changed the title Entities in ToMany reappearing after removing Entities in Backlink ToMany reappearing after removing Apr 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants