All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nbcp.myoql.db.mongo.event.MongoCascadeUpdateEvent.kt Maven / Gradle / Ivy

The newest version!
package nbcp.myoql.db.mongo.event;

import nbcp.base.comm.JsonMap
import nbcp.base.extend.*
import nbcp.base.utils.StringUtil
import nbcp.myoql.db.comm.DbEntityFieldRefData
import nbcp.myoql.db.comm.EventResult
import nbcp.myoql.db.db
import nbcp.myoql.db.enums.MyOqlDbScopeEnum
import nbcp.myoql.db.mongo.MongoBaseQueryClip
import nbcp.myoql.db.mongo.MongoEntityCollector
import nbcp.myoql.db.mongo.base.MongoColumnName
import nbcp.myoql.db.mongo.component.MongoBaseUpdateClip
import nbcp.myoql.db.mongo.extend.toDocument
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component

/**
 * 同步处理,更新的实体,级联更新引用的冗余字段。
 */

data class CascadeUpdateEventDataModel(
    var ref: DbEntityFieldRefData,
    var masterIdValues: Array,
    var dbRefValues: List
)

/**
 * 如果是级联更新数组,用下面的写法
 * DbEntityFieldRef("corp.id","corp.$.name","SysCorporation","id","name")
 */
@Component
class MongoCascadeUpdateEvent : IMongoEntityUpdate {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)
    }


    override fun beforeUpdate(update: MongoBaseUpdateClip): EventResult {
        if (scopes.getLatest(MyOqlDbScopeEnum.IGNORE_CASCADE_UPDATE) != null) {
            return EventResult(true, null)
        }


        var refs =
            MongoEntityCollector.refsMap.filter { StringUtil.getSmallCamelCase(it.refEntityClass.simpleName) == update.defEntityName }
        if (refs.any() == false) {
            return EventResult(true, null)
        }

        var list = mutableListOf()

        //update set 指定了其它表引用的冗余列。
        var updateSetFields = update.getChangedFieldData();


        //如果更新字段 和 引用字段无关,则跳过。
        var setCascadeColumns = updateSetFields.keys.intersect(refs.map { it.refNameFields }.Unwind().toSet());
        if (setCascadeColumns.any() == false) {
            //如果没有修改关联字段。直接退出。
            return EventResult(true, null)
        }
//        var masterIdFields = refs.map { it.refIdField }.toSet();


        var idValuesCache = mutableMapOf>()

        refs.forEach { ref ->
            var refNameFields = ref.refNameFields;
            if (updateSetFields.keys.intersect(refNameFields).any() == false) {
                return@forEach
            }

            var idValue = getIdValue(idValuesCache, ref, update)


            //判断新值,旧值是否相等
            val nameValueQuery = MongoBaseQueryClip(update.actualTableName)
            nameValueQuery.whereData.addAll(update.whereData)

            refNameFields.forEach {
                nameValueQuery.selectField(it)
            }

            val dbRefValues = nameValueQuery.toList(JsonMap::class.java);

            /**
             * 优化项: 如果只更新了一个字段。 单条,且值没有发生变化, 则跳过。
             */
            if (dbRefValues.size == 1 && refNameFields.size == 1) {
                var ff = refNameFields.first();
                if (dbRefValues.first().get(ff) == updateSetFields.getValue(ff)) {
                    return@forEach
                }
            }

            list.add(
                CascadeUpdateEventDataModel(
                    ref,
                    idValue,
                    dbRefValues
                )
            )
        }

        return EventResult(true, list)
    }

    private fun getIdValue(
        idValuesCache: MutableMap>,
        ref: DbEntityFieldRefData,
        update: MongoBaseUpdateClip
    ): Array {

        var idValue = idValuesCache.getOrPut(ref.refIdField) {
            //如果按id更新。
            var whereMap = db.mongo.getMergedMongoCriteria(update.whereData).toDocument();

            val refIdField = whereMap.keys.firstOrNull { key ->
                if (key == ref.refIdField) {
                    return@firstOrNull true
                }

                if (key == "_id" && ref.refIdField == "id") {
                    return@firstOrNull true
                }

                if (key.endsWith("._id") && ref.refIdField.endsWith(".id") &&
                    key.Slice(0, -4) == ref.refIdField.Slice(0, -3)
                ) {
                    return@firstOrNull true;
                }

                return@firstOrNull false
            }


            if (refIdField != null) {
                return@getOrPut arrayOf(whereMap.getStringValue(refIdField).AsString())
            }

            //查询数据,把Id查出来。
            val IdValueQuery = MongoBaseQueryClip(update.actualTableName)
            IdValueQuery.whereData.addAll(update.whereData)
            IdValueQuery.selectField(ref.refIdField)

            return@getOrPut IdValueQuery.toList(String::class.java).toTypedArray()
        }
        return idValue
    }

    override fun update(update: MongoBaseUpdateClip, eventData: EventResult) {
        if (eventData.extData == null) {
            return;
        }

        var cascadeUpdates = eventData.extData as Collection
        if (cascadeUpdates.any() == false) return;

        var updateSetFields = update.getChangedFieldData();
        cascadeUpdates
            .filter { it.masterIdValues.any() }
            .forEach { cu ->
                val targetCollection = StringUtil.getSmallCamelCase(cu.ref.entityClass.simpleName)

                val update2 = MongoBaseUpdateClip(targetCollection)
                update2.whereData.putAll((MongoColumnName(cu.ref.field + "." + cu.ref.idField) mongoIn cu.masterIdValues).criteriaObject)

                if (cu.ref.fieldIsArray) {
                    cu.ref.refNameFields.forEach { column ->
                        var setV = updateSetFields.get(column)
                        if (setV == null) {
                            return@forEach
                        }
                        update2.setValue(cu.ref.field + ".$." + column, setV)
                    }
                } else {
                    cu.ref.refNameFields.forEach { column ->
                        var setV = updateSetFields.get(column)
                        if (setV == null) {
                            return@forEach
                        }
                        update2.setValue(cu.ref.field + "." + column, setV)
                    }
                }

                update2.exec();

                logger.Important(
                    "mongo级联更新${update2.affectRowCount}条记录,${update.actualTableName}.${cu.ref.field}(${cu.ref.idField})-->${targetCollection}(${cu.ref.refIdField}),${
                        cu.masterIdValues.joinToString(
                            ","
                        )
                    }"
                )
            }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy