Extend beforeSaveTransactionCommit() for DELETE statemend

Hi,
In my latest project, I created an extended version of JpaDataStore to handle an error when deleting a record with related other records. Unfortunately, it works only with MSSQL database. I think such functionality would be useful in the next version of jmix with support for other databases

Regards
Marcin


@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@Primary
class ExtJpaDataStore(private val messages: Messages) : JpaDataStore() {

    override fun beforeSaveTransactionCommit(
        context: SaveContext,
        savedEntities: MutableCollection<Any>,
        removedEntities: MutableCollection<Any>
    ) {
        if (context.isJoinTransaction) {
            val entities: MutableList<Any> = ArrayList(savedEntities)
            entities.addAll(removedEntities)

            val eventsInfo: List<EntityChangedEventInfo>

            val em = storeAwareLocator.getEntityManager(storeName)

            val softDeletionBefore = PersistenceHints.isSoftDeletion(em)
            try {
                em.setProperty(PersistenceHints.SOFT_DELETION, context.hints[PersistenceHints.SOFT_DELETION])
                persistenceSupport.processFlush(em, false)
                eventsInfo = entityChangedEventManager.collect(persistenceSupport.getInstances(em))
                (em.delegate as EntityManager).flush()
            } catch (e: PersistenceException) {
                val exception = e.toString()
                val pattern = uniqueConstraintViolationPattern
                val matcher = pattern.matcher(exception)
                if (matcher.find()) {
                    throw UniqueConstraintViolationException(e.message, resolveConstraintName(matcher), e)
                } else {
                    val pattern2 =
                        Regex("""The DELETE statement conflicted with the REFERENCE constraint "(.+?)"\. The conflict occurred in database "(.+?)", table "(.+?)\.(.+?)", column '(.+?)'""")

                    pattern2.find(exception)?.let { matchResult ->
                        val (constraintName, dbName, schemaName, tableName, columnName) = matchResult.destructured
                        metadata.session.classes.find { metaClazz ->
                            metadataTools.getDatabaseTable(metaClazz)?.compareTo(tableName, false) == 0
                        }?.let { metaClazz ->
                            metaClazz.properties
                                .find { prop -> metadataTools.getDatabaseColumn(prop)?.compareTo(columnName) == 0 }
                                ?.let { prop ->
                                    var name =
                                        messages.getMessage(metaClazz.getJavaClass<Any>().name.replaceLast('.', '/'))
                                    throw ReferenceConstraintViolationException(
                                        "You cannot delete a record because it is linked to another record in the table: $name",
                                        e
                                    )
                                }
                        }
                    }
                }
                throw e
            } finally {
                em.setProperty(PersistenceHints.SOFT_DELETION, softDeletionBefore)
            }

            val events: MutableList<EntityChangedEvent<*>> = ArrayList(eventsInfo.size)
            for (info in eventsInfo) {
                events.add(
                    EntityChangedEvent(
                        info.source,
                        Id.of(info.entity), info.type, info.changes, info.originalMetaClass
                    )
                )
            }

            for (entity in entities) {
                detachEntity(em, entity, context.fetchPlans[entity], true)
            }

            entityChangedEventManager.publish(events)
        }
    }

}