如何使用 Xodus DNQ 级联删除最后一个链接的项目

How to cascade deletion of last linked item with Xodus DNQ

我有两个实体; municipalitycity (实际上更多,但在这里简化)。 municipality 必须始终包含至少一个城市。

有没有办法设置一个约束条件,使最终 city 级联的删除也删除其父级 municipality


实体

class XdCity(entity: Entity) : XdEntity(entity) {
    companion object : XdNaturalEntityType<XdCity>()

    var name by xdRequiredStringProp()
    var municipality: XdMunicipality by xdLink1(
        XdMunicipality::cities,
        onDelete = OnDeletePolicy.CLEAR,
        onTargetDelete = OnDeletePolicy.CASCADE
    )
}
class XdMunicipality(entity: Entity) : XdEntity(entity) {
    companion object : XdNaturalEntityType<XdMunicipality>()

    var name by xdRequiredStringProp(unique = true)
    val cities by xdLink1_N(
        XdCity::municipality,
        onDelete = OnDeletePolicy.CASCADE,
        onTargetDelete = OnDeletePolicy.CLEAR
    )
}

测试用例

@Test
fun testCityDeletionCascade() {
    Database.store.transactional {
        val municipality = XdMunicipality.findOrNew("Mun 1")
        XdCity.findOrNew("City A").apply {
            this.municipality = municipality
        }
        XdCity.findOrNew("City B").apply {
            this.municipality = municipality
        }
    }

    Database.store.transactional { 
        XdCity.all().first().delete()
        assertTrue { XdMunicipality.all().isNotEmpty }

        XdCity.all().first().delete()            
        assertTrue { XdMunicipality.all().isEmpty }
    }
}

Xodus-dnq 有两种机制:XdEntityListenerXdEntity#beforeFlush。两者都可以在这里应用。对于 beforeFlush

class XdMunicipality(entity: Entity) : XdEntity(entity) {
        companion object : XdNaturalEntityType<XdMunicipality>()

        var name by xdRequiredStringProp(unique = true)
        val cities by xdLink1_N(
             XdCity::municipality,
             onDelete = OnDeletePolicy.CASCADE,
             onTargetDelete = OnDeletePolicy.CLEAR
        )

        override fun beforeFlush() {
            if (cities.isEmpty) {
                delete()
            }
        }
    }

这两种机制仅在事务刷新时调用。所以测试应该这样修改:

@Test
    fun testCityDeletionCascade() {
        store.transactional {
            val municipality = XdMunicipality.findOrNew { name = "Mun 1" }
            XdCity.findOrNew { name = "City A" }.apply {
                this.municipality = municipality
            }
            XdCity.findOrNew { name = "City B" }.apply {
                this.municipality = municipality
            }
        }

        store.transactional {
            XdCity.all().first().delete()
            assertTrue { XdMunicipality.all().isNotEmpty }
        }
        store.transactional {
            XdCity.all().first().delete()
        }
        store.transactional {
            assertTrue { XdMunicipality.all().isEmpty }
        }
    }