Skip to content

The changes tracker sometimes misses a link deletion updates #55

@sedovalx

Description

@sedovalx

Here is the case:

class Group(entity: Entity) : XdEntity(entity) {
    companion object : XdNaturalEntityType<Group>() {
        fun new() = new {
            this.resource = Resource.new()
        }
    }

    var resource by xdLink1(Resource, onDelete = OnDeletePolicy.CASCADE, onTargetDelete = OnDeletePolicy.FAIL)

    override fun beforeFlush() {
        super.beforeFlush()

        if (hasChanges(Group::resource) && getOldValue(Group::resource) != null) {
            throw RuntimeException("Can't change resource")
        }
    }
}

class Service(entity: Entity) : XdEntity(entity) {
    companion object : XdNaturalEntityType<Service>() {
        val instance by xdSingleton()
    }

    val resources by xdChildren0_N(Resource::service)
}

class Resource(entity: Entity) : XdEntity(entity) {
    companion object : XdNaturalEntityType<Resource>() {
        fun new() = new {
            this.service = Service.instance
        }
    }

    var service: Service by xdParent(Service::resources)
}

class TestCase {
    @Test
    fun `should throw on changing resource`() {
        XdModel.registerNodes(Group, Resource, Service)
        val dir = Files.createTempDirectory("xodus")
        val store = StaticStoreContainer.init(dir.toFile(), "test")
        initMetaData(XdModel.hierarchy, store)

        val group1 = store.transactional { Group.new() }
        val group2 = store.transactional { Group.new() }

        assertThrows<RuntimeException> {
            store.transactional {
                group1.resource.delete()
                group1.resource = group2.resource
            }
        }
    }
}

The exceptions is never thrown in this case as there is no old value for the resource property. As for the changes tracker, here is what it contains on the moment of the beforeFlush execution:
image

The example above works as expected if I put the explicit resource deletion after the assignment:

group1.resource = group2.resource
group1.resource.delete()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions