diff --git a/src/main/kotlin/org/sirius/dorm/ObjectManager.kt b/src/main/kotlin/org/sirius/dorm/ObjectManager.kt index 52e7a31..efa4484 100644 --- a/src/main/kotlin/org/sirius/dorm/ObjectManager.kt +++ b/src/main/kotlin/org/sirius/dorm/ObjectManager.kt @@ -21,6 +21,7 @@ import org.antlr.v4.runtime.RecognitionException import org.sirius.common.type.base.long import org.sirius.dorm.query.parser.OQLParser import org.springframework.beans.factory.annotation.Autowired +import org.springframework.jdbc.core.JdbcTemplate import org.springframework.stereotype.Component import org.springframework.transaction.PlatformTransactionManager import java.util.concurrent.ConcurrentHashMap @@ -74,6 +75,8 @@ class ObjectManager() { private lateinit var transactionManager: PlatformTransactionManager @Autowired lateinit var mapper: DataObjectMapper + @Autowired + lateinit var jdbcTemplate: JdbcTemplate @Autowired private lateinit var objectDescriptorStorage: ObjectDescriptorStorage diff --git a/src/main/kotlin/org/sirius/dorm/object/DataObject.kt b/src/main/kotlin/org/sirius/dorm/object/DataObject.kt index af368f8..a566f6b 100644 --- a/src/main/kotlin/org/sirius/dorm/object/DataObject.kt +++ b/src/main/kotlin/org/sirius/dorm/object/DataObject.kt @@ -68,6 +68,10 @@ class DataObject(val type: ObjectDescriptor, status: Status, var state : ObjectS return values[property(name).index] as T } + fun relation(index: Int) : T { + return values[index] as T + } + operator fun get(name: String) : Any? { return values[property(name).index].get(objectManager) } diff --git a/src/main/kotlin/org/sirius/dorm/persistence/entity/PropertyEntity.kt b/src/main/kotlin/org/sirius/dorm/persistence/entity/PropertyEntity.kt index 241f63c..2b8fb96 100644 --- a/src/main/kotlin/org/sirius/dorm/persistence/entity/PropertyEntity.kt +++ b/src/main/kotlin/org/sirius/dorm/persistence/entity/PropertyEntity.kt @@ -46,8 +46,8 @@ data class PropertyEntity( @ManyToMany(fetch = FetchType.LAZY, cascade = [CascadeType.REMOVE]) @JoinTable( name = "RELATIONS", - joinColumns = [JoinColumn(name = "FROM_ENTITY"), JoinColumn(name = "FROM_")], - inverseJoinColumns = [JoinColumn(name = "TO_ENTITY"), JoinColumn(name = "TO_")] + joinColumns = [JoinColumn(name = "FROM_ATTR"), JoinColumn(name = "FROM_ENTITY")], + inverseJoinColumns = [JoinColumn(name = "TO_ATTR"), JoinColumn(name = "TO_ENTITY")] ) val targets : MutableSet = HashSet(), diff --git a/src/main/kotlin/org/sirius/dorm/transaction/TransactionState.kt b/src/main/kotlin/org/sirius/dorm/transaction/TransactionState.kt index 1648d11..c583f25 100644 --- a/src/main/kotlin/org/sirius/dorm/transaction/TransactionState.kt +++ b/src/main/kotlin/org/sirius/dorm/transaction/TransactionState.kt @@ -5,9 +5,14 @@ package org.sirius.dorm.transaction * All rights reserved */ -import org.sirius.dorm.`object`.DataObject +import jakarta.persistence.criteria.CriteriaBuilder +import jakarta.persistence.criteria.CriteriaDelete +import jakarta.persistence.criteria.Root import org.sirius.dorm.ObjectManager +import org.sirius.dorm.model.Cascade import org.sirius.dorm.model.ObjectDescriptor +import org.sirius.dorm.`object`.DataObject +import org.sirius.dorm.`object`.Relation import org.sirius.dorm.persistence.DataObjectMapper import org.sirius.dorm.persistence.entity.EntityEntity import org.springframework.transaction.PlatformTransactionManager @@ -15,6 +20,7 @@ import org.springframework.transaction.TransactionDefinition import org.springframework.transaction.TransactionStatus import org.springframework.transaction.support.DefaultTransactionDefinition + abstract class Operation() { abstract fun execute() } @@ -47,15 +53,74 @@ class TransactionState(val objectManager: ObjectManager, val transactionManager: pendingOperations.clear() } + + fun processDeletedObjects() { + val objects = states.values.filter { state -> state.status == Status.DELETED } + + // this is the set of deleted objects + + val ids = HashSet()//objects.map { state -> state.obj.id }.toHashSet() + + val queue : MutableList = objects.map { state -> state.obj.id}.toMutableList() + while ( queue.isNotEmpty()) { + val id = queue.removeAt(0); + + if (!ids.contains(id)) { + ids.add(id) + + if (states.containsKey(id)) { + val obj = states[id]!!.obj + + obj.state?.status = Status.DELETED + + var i = 0 + for (property in obj.type.properties) { + if (!property.isAttribute() && property.asRelation().cascade == Cascade.DELETE) { + val relation = obj.relation(i) + + if (relation.isLoaded()) { + for (r in relation.relations()) + queue.add(r.entity.id) + } + else { // FROM_ATTR | FROM_ENTITY | TO_ATTR | TO_ENTITY | + objectManager.jdbcTemplate.query("SELECT DISTINCT TO_ENTITY FROM RELATIONS WHERE FROM_ENTITY = ${id} AND FROM_ATTR='${property.name}'") { rs, _ -> + rs.getLong("TO_ENTITY") + }.forEach { id -> queue.add(id) } + } + } // if + + i++ + } // for + } // if + } // if + } // while + + // finally delete + + val entityManager = objectManager.entityManager + + val criteriaBuilder = entityManager.getCriteriaBuilder() + + val criteriaDelete = criteriaBuilder.createCriteriaDelete(EntityEntity::class.java) + + val root = criteriaDelete.from(EntityEntity::class.java) + + criteriaDelete.where( criteriaBuilder.isTrue(root.get("id").`in`(*ids.toTypedArray()))) + + entityManager.createQuery(criteriaDelete).executeUpdate() + } + // TX fun commit(mapper: DataObjectMapper) { + processDeletedObjects() + // commit changes for (state in states.values) { when ( state.status) { Status.CREATED -> mapper.create(this, state.obj) - Status.DELETED -> mapper.delete(this, state.obj) + Status.DELETED -> { /* already processed */}//mapper.delete(this, state.obj) Status.MANAGED -> { if ( state.isDirty()) mapper.update(this, state.obj)