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

com.gitee.qdbp.jdbc.biz.CrudDaoImpl Maven / Gradle / Ivy

package com.gitee.qdbp.jdbc.biz;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitee.qdbp.able.convert.MapToBeanConverter;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.condition.DbUpdate;
import com.gitee.qdbp.able.jdbc.condition.DbWhere;
import com.gitee.qdbp.able.jdbc.fields.Fields;
import com.gitee.qdbp.able.jdbc.fields.IncludeFields;
import com.gitee.qdbp.able.jdbc.model.PkEntity;
import com.gitee.qdbp.able.jdbc.ordering.Orderings;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.jdbc.api.CrudDao;
import com.gitee.qdbp.jdbc.api.SqlBoot;
import com.gitee.qdbp.jdbc.api.SqlBufferJdbcOperations;
import com.gitee.qdbp.jdbc.api.SqlDao;
import com.gitee.qdbp.jdbc.api.SqlOperator;
import com.gitee.qdbp.jdbc.exception.DbErrorCode;
import com.gitee.qdbp.jdbc.model.AllFieldColumn;
import com.gitee.qdbp.jdbc.model.DbVersion;
import com.gitee.qdbp.jdbc.model.FieldScene;
import com.gitee.qdbp.jdbc.model.SimpleFieldColumn;
import com.gitee.qdbp.jdbc.model.ValidStrategy;
import com.gitee.qdbp.jdbc.plugins.BatchInsertExecutor;
import com.gitee.qdbp.jdbc.plugins.BatchUpdateExecutor;
import com.gitee.qdbp.jdbc.plugins.DbConditionConverter;
import com.gitee.qdbp.jdbc.plugins.DbPluginHelper;
import com.gitee.qdbp.jdbc.plugins.EntityDataStateFillStrategy;
import com.gitee.qdbp.jdbc.plugins.EntityFieldFillExecutor;
import com.gitee.qdbp.jdbc.plugins.EntityFieldFillStrategy;
import com.gitee.qdbp.jdbc.plugins.SqlDialect;
import com.gitee.qdbp.jdbc.sql.SqlBuffer;
import com.gitee.qdbp.jdbc.sql.SqlBuilder;
import com.gitee.qdbp.jdbc.sql.SqlTools;
import com.gitee.qdbp.jdbc.sql.build.CommonSqlTools;
import com.gitee.qdbp.jdbc.sql.build.CrudSqlHelper;
import com.gitee.qdbp.jdbc.sql.fragment.CrudFragmentHelper;
import com.gitee.qdbp.jdbc.sql.parse.SqlFragmentContainer;
import com.gitee.qdbp.jdbc.utils.ParseTools;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.MapTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 基础增删改查数据库操作
 *
 * @author 赵卉华
 * @version 190601
 */
public class CrudDaoImpl extends BaseQueryerImpl implements CrudDao {

    private static final Logger log = LoggerFactory.getLogger(CrudDaoImpl.class);
    protected final Class beanClass;
    protected final SqlBoot sqlBoot;
    protected final SqlDao sqlDao;
    protected final CrudSqlOperator sqlOperator;
    /** 批量执行时的大小限制(0为无限制) **/
    protected int defaultBatchSize = QdbcBootImpl.DEFAULT_BATCH_SIZE;

    CrudDaoImpl(Class c, SqlBoot sqlBoot, SqlDao sqlDao, SqlBufferJdbcOperations jdbc) {
        super(new CrudSqlHelper(c, sqlBoot), newEntityFieldFillExecutor(c, sqlBoot), jdbc,
                sqlBoot.plugins().getRowToBeanMapper(c));
        this.beanClass = c;
        this.sqlBoot = sqlBoot;
        this.sqlDao = sqlDao;
        this.sqlOperator = new CrudSqlOperator(c, sqlBoot);
    }

    private static EntityFieldFillExecutor newEntityFieldFillExecutor(Class clazz, SqlBoot sqlBoot) {
        DbPluginHelper plugins = sqlBoot.plugins();
        AllFieldColumn allFields = plugins.parseAllFieldColumns(clazz);
        EntityFieldFillStrategy fieldFillStrategy = plugins.getEntityFieldFillStrategy();
        EntityDataStateFillStrategy dataStateFillStrategy = plugins.getEntityDataStateFillStrategy();
        return new EntityFieldFillExecutor(allFields, fieldFillStrategy, dataStateFillStrategy);
    }

    @Override
    public CrudSqlHelper sqlHelper() {
        return (CrudSqlHelper) this.sqlHelper;
    }

    @Override
    public T findById(Serializable id) {
        return findById(Fields.ALL, id);
    }

    @Override
    public T findById(Fields fields, Serializable id) {
        VerifyTools.requireNotBlank(id, "id");
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedFindById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details);
        }
        String primaryField = pk.getFieldName();
        DbWhere where = new DbWhere().on(primaryField).equals(id).end();
        return this.find(fields, where);
    }

    @Override
    public List listByIds(Collection ids, Orderings orderings) throws ServiceException {
        VerifyTools.requireNotBlank(ids, "ids");
        return listByIds(Fields.ALL, ids, orderings);
    }

    @Override
    public List listByIds(Fields fields, Collection ids, Orderings orderings)
            throws ServiceException {
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedListByIds, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details);
        }
        String primaryField = pk.getFieldName();
        DbWhere where = new DbWhere().on(primaryField).in(ids).end();
        return list(fields, where, orderings);
    }

    @Override
    public List listChildren(String startCode, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCode, "startCode");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        List startCodes = Collections.singletonList(startCode);
        return doListChildren(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    @Override
    public List listChildren(List startCodes, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCodes, "startCodes");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        return doListChildren(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    private List doListChildren(List startCodes, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        DbWhere filter = checkWhere(filterWhere);
        DbWhere search = checkWhere(searchWhere);
        // 数据状态填充在filterWhere中
        entityFieldFillExecutor.fillQueryWhereDataState(filter, getMajorTableAlias());
        // 数据权限填充在searchWhere中
        entityFieldFillExecutor.fillQueryWhereParams(search, getMajorTableAlias());

        return doListChildren(startCodes, codeField, parentField, Fields.ALL, filter, search, orderings, beanClass);
    }

    @Override
    public List listChildrenCodes(String startCode, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCode, "startCode");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        List startCodes = Collections.singletonList(startCode);
        return doListChildrenCodes(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    @Override
    public List listChildrenCodes(List startCodes, String codeField, String parentField,
            DbWhere filterWhere, DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCodes, "startCodes");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        return doListChildrenCodes(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    private List doListChildrenCodes(List startCodes, String codeField, String parentField,
            DbWhere filterWhere, DbWhere searchWhere, Orderings orderings) {
        DbWhere filter = checkWhere(filterWhere);
        DbWhere search = checkWhere(searchWhere);
        // 数据状态填充在filterWhere中
        entityFieldFillExecutor.fillQueryWhereDataState(filter, getMajorTableAlias());
        // 数据权限填充在searchWhere中
        entityFieldFillExecutor.fillQueryWhereParams(search, getMajorTableAlias());

        IncludeFields fields = new IncludeFields(codeField);
        return doListChildren(startCodes, codeField, parentField, fields, filter, search, orderings, String.class);
    }

    @Override
    public List listParents(String startCode, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCode, "startCode");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        List startCodes = Collections.singletonList(startCode);
        return doListParents(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    @Override
    public List listParents(List startCodes, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCodes, "startCodes");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        return doListParents(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    private List doListParents(List startCodes, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        DbWhere filter = checkWhere(filterWhere);
        DbWhere search = checkWhere(searchWhere);
        // 数据状态填充在filterWhere中
        entityFieldFillExecutor.fillQueryWhereDataState(filter, getMajorTableAlias());
        // 数据权限填充在searchWhere中
        entityFieldFillExecutor.fillQueryWhereParams(search, getMajorTableAlias());

        if (orderings != null && !orderings.isEmpty()) {
            return doListParents(startCodes, codeField, parentField, Fields.ALL, filter, search, orderings, beanClass);
        } else {
            // 如果startCode只有一个, 且未指定排序字段, 则结果会保证顺序从顶级节点开始依次排列
            Map params = generateRecursiveParams(startCodes, codeField, parentField, Fields.ALL,
                    filterWhere, searchWhere, orderings);

            String sqlId = "GlobalRecursive:recursiveListParentsQuery";
            List> list = sqlDao.listForMaps(sqlId, params);

            List> sorted = MapTools.sortTreeNodes(list, codeField, parentField);

            List results = new ArrayList<>();
            MapToBeanConverter converter = sqlBoot.plugins().getMapToBeanConverter();
            for (Map item : sorted) {
                T entity = converter.convert(item, beanClass);
                results.add(entity);
            }
            return results;
        }
    }

    @Override
    public List listParentCodes(String startCode, String codeField, String parentField, DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCode, "startCode");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        List startCodes = Collections.singletonList(startCode);
        return doListParentCodes(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    @Override
    public List listParentCodes(List startCodes, String codeField, String parentField,
            DbWhere filterWhere, DbWhere searchWhere, Orderings orderings) {
        VerifyTools.requireNotBlank(startCodes, "startCodes");
        VerifyTools.requireNotBlank(codeField, "codeField");
        VerifyTools.requireNotBlank(parentField, "parentField");

        return doListParentCodes(startCodes, codeField, parentField, filterWhere, searchWhere, orderings);
    }

    private List doListParentCodes(List startCodes, String codeField, String parentField,
            DbWhere filterWhere,
            DbWhere searchWhere, Orderings orderings) {
        DbWhere filter = checkWhere(filterWhere);
        DbWhere search = checkWhere(searchWhere);
        // 数据状态填充在filterWhere中
        entityFieldFillExecutor.fillQueryWhereDataState(filter, getMajorTableAlias());
        // 数据权限填充在searchWhere中
        entityFieldFillExecutor.fillQueryWhereParams(search, getMajorTableAlias());

        if (orderings != null && !orderings.isEmpty()) {
            IncludeFields fields = new IncludeFields(codeField);
            return doListParents(startCodes, codeField, parentField, fields, filter, search, orderings,
                    String.class);
        } else {
            IncludeFields fields = new IncludeFields(codeField, parentField);
            Map params = generateRecursiveParams(startCodes, codeField, parentField, fields,
                    filterWhere, searchWhere, orderings);

            String sqlId = "GlobalRecursive:recursiveListParentsQuery";
            List> list = sqlDao.listForMaps(sqlId, params);

            List> sorted = MapTools.sortTreeNodes(list, codeField, parentField);
            List results = new ArrayList<>();
            for (Map item : sorted) {
                Object codeValue = item.get(codeField);
                if (codeValue != null) {
                    results.add(codeValue.toString());
                }
            }
            return results;
        }
    }

    // ORACLE: START WITH {codeField} IN( {startCode} ) CONNECT BY PRIOR {codeField}={parentField}
    // DB2: 使用WITH递归 
    // MYSQL 8.0+: 使用WITH RECURSIVE递归 
    // MYSQL 8.0-: 使用存储过程RECURSIVE_LIST_CHILDREN_QUERY
    protected  List doListChildren(List startCodes, String codeField, String parentField, Fields fields,
            DbWhere filter, DbWhere search, Orderings orderings, Class resultType) throws ServiceException {
        return doListRecursive("Children", startCodes, codeField, parentField, fields, filter, search, orderings,
                resultType);
    }

    protected  List doListParents(List startCodes, String codeField, String parentField, Fields fields,
            DbWhere filter, DbWhere search, Orderings orderings, Class resultType) throws ServiceException {
        return doListRecursive("Parents", startCodes, codeField, parentField, fields, filter, search, orderings,
                resultType);
    }

    protected  List doListRecursive(String type, List startCodes, String codeField, String parentField,
            Fields selectFields, DbWhere filterWhere, DbWhere searchWhere, Orderings orderings, Class resultType)
            throws ServiceException {
        Map params = generateRecursiveParams(startCodes, codeField, parentField, selectFields,
                filterWhere, searchWhere, orderings);

        String sqlId = "GlobalRecursive:recursiveList" + type + "Query";
        return sqlDao.listForObjects(sqlId, params, resultType);
    }

    private Map generateRecursiveParams(List startCodes, String codeField, String parentField,
            Fields selectFields, DbWhere filterWhere, DbWhere searchWhere, Orderings orderings) {
        CrudFragmentHelper sqlHelper = sqlHelper().fragment();
        String codeColumn = sqlHelper.getColumnName(FieldScene.CONDITION, codeField);
        String parentColumn = sqlHelper.getColumnName(FieldScene.CONDITION, parentField);
        SqlBuffer selectColumns = sqlHelper.buildSelectFieldsSql(selectFields);

        Map params = new HashMap<>();
        params.put("codeColumn", codeColumn);
        params.put("parentColumn", parentColumn);
        params.put("tableName", sqlHelper.getTableName());
        params.put("selectColumns", selectColumns);
        params.put("startCodes", startCodes);
        if (filterWhere != null && !filterWhere.isEmpty()) {
            params.put("filterWhere", sqlHelper.buildWhereSql(filterWhere, false));
        }
        if (searchWhere != null && !searchWhere.isEmpty()) {
            params.put("searchWhere", sqlHelper.buildWhereSql(searchWhere, false));
        }
        if (orderings != null && !orderings.isEmpty()) {
            params.put("orderBy", sqlHelper.buildOrderBySql(orderings, false));
        }
        return params;
    }

    protected Map copmareMapDifference(Map original, Map current) {
        Map diff = new HashMap<>();
        for (Map.Entry entry : original.entrySet()) {
            if (!current.containsKey(entry.getKey())) {
                diff.put(entry.getKey(), null);
            }
        }
        for (Map.Entry entry : current.entrySet()) {
            Object curvalue = SqlTools.unwrapDbVariable(entry.getValue());
            Object orivalue = SqlTools.unwrapDbVariable(original.get(entry.getKey()));
            if (VerifyTools.notEquals(curvalue, orivalue)) {
                diff.put(entry.getKey(), curvalue);
            }
        }
        return diff;
    }

    @Override
    public String insert(T entity) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, ValidStrategy.AUTO, true);
    }

    @Override
    public String insert(T entity, boolean fillCreateParams) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, ValidStrategy.AUTO, fillCreateParams);
    }

    @Override
    public String insert(Map entity) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, ValidStrategy.AUTO, true);
    }

    @Override
    public String insert(Map entity, boolean fillCreateParams) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, ValidStrategy.AUTO, fillCreateParams);
    }

    @Override
    public String insert(T entity, ValidStrategy validStrategy) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, validStrategy, true);
    }

    @Override
    public String insert(T entity, ValidStrategy validStrategy, boolean fillCreateParams) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, validStrategy, fillCreateParams);
    }

    @Override
    public String insert(Map entity, ValidStrategy validStrategy) throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, validStrategy, true);
    }

    @Override
    public String insert(Map entity, ValidStrategy validStrategy, boolean fillCreateParams)
            throws ServiceException {
        VerifyTools.requireNonNull(entity, "entity");
        return executeInsert(entity, validStrategy, fillCreateParams);
    }

    protected String executeInsert(Object object, ValidStrategy validStrategy, boolean fillCreateParams)
            throws ServiceException {
        // 将实体类转换为map, 并执行实体业务数据填充
        PkEntity pe = convertAndFillCreateParams(object, fillCreateParams);
        String id = pe.getPrimaryKey();
        Map readyEntity = pe.getEntity();
        // 执行数据库插入
        SqlBuffer buffer = sqlHelper().buildInsertSql(readyEntity, validStrategy);
        jdbc.insert(buffer);
        return id;
    }

    @Override
    public List inserts(List entities) throws ServiceException {
        return doInserts(entities, ValidStrategy.AUTO, true, this.defaultBatchSize);
    }

    @Override
    public List inserts(List entities, boolean fillCreateParams) throws ServiceException {
        return doInserts(entities, ValidStrategy.AUTO, fillCreateParams, this.defaultBatchSize);
    }

    @Override
    public List inserts(List entities, ValidStrategy validStrategy) throws ServiceException {
        return doInserts(entities, validStrategy, true, this.defaultBatchSize);
    }

    @Override
    public List inserts(List entities, ValidStrategy validStrategy, boolean fillCreateParams)
            throws ServiceException {
        return doInserts(entities, validStrategy, fillCreateParams, this.defaultBatchSize);
    }

    protected List doInserts(List entities, ValidStrategy validStrategy, boolean fillCreateParams,
            int batchSize) throws ServiceException {
        VerifyTools.requireNotBlank(entities, "entities");
        if (entities.size() == 1) {
            Object first = entities.get(0);
            String id = executeInsert(first, validStrategy, fillCreateParams);
            return ConvertTools.toList(id);
        } else if (batchSize <= 0 || entities.size() <= batchSize) {
            return doBatchInserts(entities, validStrategy, fillCreateParams);
        } else { // 分批导入
            List ids = new ArrayList<>();
            List buffer = new ArrayList<>();
            for (int i = 1, size = entities.size(); i <= size; i++) {
                buffer.add(entities.get(i - 1));
                if (i % batchSize == 0 || i == size) {
                    List batchIds = doBatchInserts(buffer, validStrategy, fillCreateParams);
                    ids.addAll(batchIds);
                    buffer.clear();
                }
            }
            return ids;
        }
    }

    protected List doBatchInserts(List entities, ValidStrategy validStrategy, boolean fillCreateParams)
            throws ServiceException {
        List contents = new ArrayList<>();
        for (Object item : entities) {
            // 将实体类转换为map, 并执行实体业务数据填充
            PkEntity pe = convertAndFillCreateParams(item, fillCreateParams);
            contents.add(pe);
        }

        DbVersion version = jdbc.dbVersion();
        BatchInsertExecutor batchOperator = jdbc.plugins().getBatchInsertExecutor(version);
        // 执行批量数据库插入
        return batchOperator.inserts(contents, validStrategy, jdbc, sqlOperator);
    }

    @Override
    public int update(T entity) throws ServiceException {
        return this.update(entity, ValidStrategy.AUTO, true, false);
    }

    @Override
    public int update(T entity, boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException {
        return this.update(entity, ValidStrategy.AUTO, fillUpdateParams, fillUpdateParams);
    }

    @Override
    public int update(T entity, ValidStrategy validStrategy) throws ServiceException {
        return this.update(entity, validStrategy, true, false);
    }

    @Override
    public int update(T entity, ValidStrategy validStrategy, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        if (entity == null) {
            log.debug("Update set fields is empty, the update operation will be skipped.");
            return 0;
        }
        // 查找主键
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedUpdateById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details);
        }
        PkEntity pe = convertAndFillUpdateParams(entity, fillUpdateParams);
        Serializable pkValue = pe.getPrimaryKey();
        if (VerifyTools.isBlank(pkValue)) { // 主键值为空
            String details = "CanNotExecuteUpdateById, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED).setDetails(details);
        }
        // 实体类转换为DbUpdate
        DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
        DbUpdate ud = converter.parseMapToDbUpdate(pe.getEntity());
        // 生成主键限制条件
        DbWhere where = new DbWhere().on(pk.getFieldName()).equals(pkValue).end();
        entityFieldFillExecutor.fillUpdateWhereDataState(where);
        entityFieldFillExecutor.fillUpdateWhereParams(where);
        return this.doUpdate(ud, where, validStrategy, errorOnUnaffected);
    }

    @Override
    public int update(Map entity) throws ServiceException {
        return this.update(entity, ValidStrategy.AUTO, true, false);
    }

    @Override
    public int update(Map entity, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        return this.update(entity, ValidStrategy.AUTO, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int update(Map entity, ValidStrategy validStrategy) throws ServiceException {
        return this.update(entity, validStrategy, true, false);
    }

    @Override
    public int update(Map entity, ValidStrategy validStrategy, boolean fillUpdateParams,
            boolean errorOnUnaffected) throws ServiceException {
        if (entity == null || entity.isEmpty()) {
            log.debug("Update set fields is empty, the update operation will be skipped.");
            return 0;
        }
        DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
        if (!entity.containsKey("where")) { // 没有where条件, 必须要有主键
            if (entity.isEmpty()) {
                String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details);
            }
            // 查找主键
            SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
            if (pk == null) { // 没有找到主键字段
                String details = "UnsupportedUpdateById, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details);
            }
            Object value = entity.get(pk.getFieldName());
            if (VerifyTools.isBlank(value)) { // 主键值为空
                String details = "CanNotExecuteUpdateById, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED).setDetails(details);
            }
            Serializable pkValue;
            if (value instanceof Serializable) {
                pkValue = (Serializable) value;
            } else {
                pkValue = value.toString();
            }
            // 填充实体的修改参数(如修改人修改时间等)
            fillEntityUpdateParams(entity, fillUpdateParams);
            // 转换为DbUpdate对象
            DbUpdate ud = converter.parseMapToDbUpdate(entity);
            // 生成主键查询条件
            DbWhere where = new DbWhere().on(pk.getFieldName()).equals(pkValue).end();
            // 填充Where条件
            entityFieldFillExecutor.fillUpdateWhereDataState(where);
            entityFieldFillExecutor.fillUpdateWhereParams(where);
            return this.doUpdate(ud, where, validStrategy, errorOnUnaffected);
        } else { // 如果Update对象中带有where字段, 将where字段值转换为DbWhere对象
            Object whereValue = entity.remove("where");
            DbWhere where;
            if (whereValue == null) {
                where = null;
            } else if (whereValue instanceof DbWhere) {
                where = (DbWhere) whereValue;
            } else if (whereValue instanceof Map) {
                @SuppressWarnings("unchecked")
                Map mapValue = (Map) whereValue;
                where = converter.parseMapToDbWhere(mapValue);
            } else if (beanClass.isAssignableFrom(whereValue.getClass())) {
                @SuppressWarnings("unchecked")
                T entityValue = (T) whereValue;
                where = converter.convertBeanToDbWhere(entityValue);
            } else {
                // whereValue只支持DbWhere/map/T
                String details = "CanNotExecuteUpdate, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_UNSUPPORTED_WHERE_TYPE).setDetails(details);
            }
            if (entity.isEmpty()) {
                String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details);
            }
            // 填充实体的修改参数(如修改人修改时间等)
            fillEntityUpdateParams(entity, fillUpdateParams);
            // 转换为DbUpdate对象
            DbUpdate ud = converter.parseMapToDbUpdate(entity);
            // 检查Where条件
            DbWhere readyWhere = checkWhere(where);
            // 填充Where条件
            entityFieldFillExecutor.fillUpdateWhereDataState(where);
            entityFieldFillExecutor.fillUpdateWhereParams(where);
            return this.doUpdate(ud, readyWhere, validStrategy, errorOnUnaffected);
        }
    }

    @Override
    public int update(T entity, DbWhere where) throws ServiceException {
        return this.update(entity, where, ValidStrategy.AUTO, true, false);
    }

    @Override
    public int update(T entity, DbWhere where, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        return this.update(entity, where, ValidStrategy.AUTO, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int update(T entity, DbWhere where, ValidStrategy validStrategy) throws ServiceException {
        return this.update(entity, where, validStrategy, true, false);
    }

    @Override
    public int update(T entity, DbWhere where, ValidStrategy validStrategy, boolean fillUpdateParams,
            boolean errorOnUnaffected) throws ServiceException {
        if (entity == null) {
            log.debug("Update set fields is empty, the update operation will be skipped.");
            return 0;
        }
        Map mapEntity = convertEntityAndFillUpdateParams(entity, fillUpdateParams);
        DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
        DbUpdate readyEntity = converter.parseMapToDbUpdate(mapEntity);
        if (readyEntity.isEmpty()) {
            String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details);
        }

        DbWhere readyWhere = checkWhere(where);
        entityFieldFillExecutor.fillUpdateWhereDataState(readyWhere);
        entityFieldFillExecutor.fillUpdateWhereParams(readyWhere);
        return this.doUpdate(readyEntity, readyWhere, validStrategy, errorOnUnaffected);
    }

    @Override
    public int update(DbUpdate entity, DbWhere where) throws ServiceException {
        return this.update(entity, where, ValidStrategy.AUTO, true, false);
    }

    @Override
    public int update(DbUpdate entity, DbWhere where, boolean fillUpdateParams, boolean errorOnUnaffected)
            throws ServiceException {
        return this.update(entity, where, ValidStrategy.AUTO, fillUpdateParams, errorOnUnaffected);
    }

    @Override
    public int update(DbUpdate entity, DbWhere where, ValidStrategy validStrategy) throws ServiceException {
        return this.update(entity, where, validStrategy, true, false);
    }

    @Override
    public int update(DbUpdate entity, DbWhere where, ValidStrategy validStrategy, boolean fillUpdateParams,
            boolean errorOnUnaffected) throws ServiceException {
        if (entity == null || entity.isEmpty()) {
            log.debug("Update set fields is empty, the update operation will be skipped.");
            return 0;
        }
        DbWhere readyWhere = checkWhere(where);
        entityFieldFillExecutor.fillUpdateWhereDataState(readyWhere);
        entityFieldFillExecutor.fillUpdateWhereParams(readyWhere);
        // 不需要自动填充修改时的数据状态标记, 没有这样的业务场景
        // entityFieldFillExecutor.fillEntityUpdateDataState(entity);
        if (fillUpdateParams) {
            entityFieldFillExecutor.fillEntityUpdateParams(entity);
        }
        return this.doUpdate(entity, readyWhere, validStrategy, errorOnUnaffected);
    }

    protected int doUpdate(DbUpdate readyEntity, DbWhere readyWhere, ValidStrategy validStrategy,
            boolean errorOnUnaffected) throws ServiceException {
        SqlBuffer buffer = sqlHelper().buildUpdateSql(readyEntity, readyWhere, validStrategy);
        int rows;
        if (buffer.isBlank()) {
            rows = 0;
            log.debug("Update set fields is empty, the update operation will be skipped.");
        } else {
            rows = jdbc.update(buffer);
        }

        if (rows == 0 && errorOnUnaffected) {
            throw new ServiceException(DbErrorCode.DB_AFFECTED_ROWS_IS_ZERO);
        }
        return rows;
    }

    @Override
    public int updates(List entities) throws ServiceException {
        return updates(entities, ValidStrategy.AUTO, true, this.defaultBatchSize);
    }

    @Override
    public int updates(List entities, boolean fillUpdateParams) throws ServiceException {
        return updates(entities, ValidStrategy.AUTO, fillUpdateParams, this.defaultBatchSize);
    }

    @Override
    public int updates(List entities, ValidStrategy validStrategy) throws ServiceException {
        return updates(entities, validStrategy, true, this.defaultBatchSize);
    }

    @Override
    public int updates(List entities, ValidStrategy validStrategy, boolean fillUpdateParams)
            throws ServiceException {
        return updates(entities, validStrategy, fillUpdateParams, this.defaultBatchSize);
    }

    protected int updates(List entities, ValidStrategy validStrategy, boolean fillUpdateParams, int batchSize)
            throws ServiceException {
        VerifyTools.requireNotBlank(entities, "entities");
        // 查找主键(批量更新必须要有主键)
        SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedBatchUpdate, class=" + beanClass.getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details);
        }
        if (entities.size() == 1) {
            Object first = entities.get(0);
            // 将实体类转换为map, 并执行实体业务数据填充
            PkEntity pe = convertAndFillUpdateParams(first, fillUpdateParams);
            Serializable pkValue = pe.getPrimaryKey();
            if (VerifyTools.isBlank(pkValue)) { // 主键值为空
                String details = "UnsupportedBatchUpdate, class=" + beanClass.getName();
                throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED).setDetails(details);
            }
            // 实体类转换为DbUpdate
            DbConditionConverter converter = jdbc.plugins().getDbConditionConverter();
            DbUpdate ud = converter.parseMapToDbUpdate(pe.getEntity());
            // 生成主键限制条件
            DbWhere where = new DbWhere().on(pk.getFieldName()).equals(pkValue).end();
            // 与批量处理的逻辑保持一致, 不限制数据状态
            // entityFieldFillExecutor fillUpdateWhereDataState(where);
            // entityFieldFillExecutor fillUpdateWhereParams(where);
            return this.doUpdate(ud, where, validStrategy, false);
        } else if (batchSize <= 0 || entities.size() <= batchSize) {
            return doBatchUpdates(entities, validStrategy, fillUpdateParams);
        } else { // 分批导入
            List buffer = new ArrayList<>();
            int rows = 0;
            for (int i = 1, size = entities.size(); i <= size; i++) {
                buffer.add(entities.get(i - 1));
                if (i % batchSize == 0 || i == size) {
                    rows += doBatchUpdates(buffer, validStrategy, fillUpdateParams);
                    buffer.clear();
                }
            }
            return rows;
        }
    }

    /**
     * 执行批量更新
     *
     * @param entities 实体对象列表(只能是entity或map或IdEntity列表, 其他参数将会报错)
     * @param validStrategy 校验处理策略
* 注意: 由于@Column的length/precision/scale有默认值, 一旦启用, 则所有字段都需要覆盖设置! * @param fillUpdateParams 是否自动填充更新参数(修改人/修改时间等) * @return 受影响行数 * @throws ServiceException 操作失败 */ protected int doBatchUpdates(List entities, ValidStrategy validStrategy, boolean fillUpdateParams) throws ServiceException { List contents = new ArrayList<>(); for (Object item : entities) { // 将实体类转换为map, 并执行实体业务数据填充 PkEntity pkud = convertAndFillUpdateParams(item, fillUpdateParams); contents.add(pkud); } DbVersion version = jdbc.dbVersion(); BatchUpdateExecutor batchOperator = jdbc.plugins().getBatchUpdateExecutor(version); // 执行批量数据库更新 return batchOperator.updates(contents, validStrategy, jdbc, sqlOperator); } @Override public int logicalDeleteById(Serializable id) throws ServiceException { VerifyTools.requireNotBlank(id, "id"); return logicalDeleteById(id, true, false); } @Override public int logicalDeleteById(Serializable id, boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException { VerifyTools.requireNotBlank(id, "id"); SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey(); if (pk == null) { // 没有找到主键字段 String details = "UnsupportedDeleteById, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details); } String primaryField = pk.getFieldName(); DbWhere where = new DbWhere().on(primaryField).equals(id).end(); entityFieldFillExecutor.fillDeleteWhereDataState(where); entityFieldFillExecutor.fillDeleteWhereParams(where); return this.doDelete(where, false, fillUpdateParams, errorOnUnaffected); } @Override public int logicalDeleteByIds(Collection ids) throws ServiceException { return logicalDeleteByIds(ids, true, false); } @Override public int logicalDeleteByIds(Collection ids, boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException { VerifyTools.requireNotBlank(ids, "ids"); SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey(); if (pk == null) { // 没有找到主键字段 String details = "UnsupportedDeleteById, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details); } String primaryField = pk.getFieldName(); DbWhere where = new DbWhere().on(primaryField).in(ids).end(); entityFieldFillExecutor.fillDeleteWhereDataState(where); entityFieldFillExecutor.fillDeleteWhereParams(where); return this.doDelete(where, false, fillUpdateParams, errorOnUnaffected); } @Override public int logicalDelete(T where) throws ServiceException { return logicalDelete(where, true, false); } @Override public int logicalDelete(T where, boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException { if (where == null) { String details = "If you want to delete all records, please use DbWhere.NONE"; throw new ServiceException(DbErrorCode.DB_WHERE_MUST_NOT_BE_EMPTY).setDetails(details); } DbConditionConverter converter = jdbc.plugins().getDbConditionConverter(); DbWhere beanWhere = converter.convertBeanToDbWhere(where); DbWhere readyWhere = checkWhere(beanWhere); entityFieldFillExecutor.fillDeleteWhereDataState(readyWhere); entityFieldFillExecutor.fillDeleteWhereParams(readyWhere); return this.doDelete(readyWhere, false, fillUpdateParams, errorOnUnaffected); } @Override public int logicalDelete(DbWhere where) throws ServiceException { return logicalDelete(where, true, false); } @Override public int logicalDelete(DbWhere where, boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException { DbWhere readyWhere = checkWhere(where); entityFieldFillExecutor.fillDeleteWhereDataState(readyWhere); entityFieldFillExecutor.fillDeleteWhereParams(readyWhere); return this.doDelete(readyWhere, false, fillUpdateParams, errorOnUnaffected); } @Override public int physicalDeleteById(Serializable id) throws ServiceException { return physicalDeleteById(id, false); } @Override public int physicalDeleteById(Serializable id, boolean errorOnUnaffected) throws ServiceException { VerifyTools.requireNotBlank(id, "id"); SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey(); if (pk == null) { // 没有找到主键字段 String details = "UnsupportedDeleteById, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details); } String primaryField = pk.getFieldName(); DbWhere where = new DbWhere().on(primaryField).equals(id).end(); return this.doDelete(where, true, false, errorOnUnaffected); } @Override public int physicalDeleteByIds(Collection ids) throws ServiceException { return physicalDeleteByIds(ids, false); } @Override public int physicalDeleteByIds(Collection ids, boolean errorOnUnaffected) throws ServiceException { VerifyTools.requireNotBlank(ids, "ids"); SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey(); if (pk == null) { // 没有找到主键字段 String details = "UnsupportedDeleteById, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details); } String primaryField = pk.getFieldName(); DbWhere where = new DbWhere().on(primaryField).in(ids).end(); return this.doDelete(where, true, false, errorOnUnaffected); } @Override public int physicalDelete(T where) throws ServiceException { return physicalDelete(where, false); } @Override public int physicalDelete(T where, boolean errorOnUnaffected) throws ServiceException { if (where == null) { String details = "If you want to delete all records, please use DbWhere.NONE"; throw new ServiceException(DbErrorCode.DB_WHERE_MUST_NOT_BE_EMPTY).setDetails(details); } DbConditionConverter converter = jdbc.plugins().getDbConditionConverter(); DbWhere beanWhere = converter.convertBeanToDbWhere(where); DbWhere readyWhere = checkWhere(beanWhere); return this.doDelete(readyWhere, true, false, errorOnUnaffected); } @Override public int physicalDelete(DbWhere where) throws ServiceException { return this.doDelete(where, true, false, false); } @Override public int physicalDelete(DbWhere where, boolean errorOnUnaffected) throws ServiceException { return this.doDelete(where, true, false, errorOnUnaffected); } protected int doDelete(DbWhere readyWhere, boolean physical, boolean fillUpdateParams, boolean errorOnUnaffected) throws ServiceException { int rows; if (physical) { // 物理删除 SqlBuffer buffer = sqlHelper().buildDeleteSql(readyWhere); rows = jdbc.delete(buffer); } else { // 逻辑删除 if (entityFieldFillExecutor.supportedTableLogicalDelete()) { // 支持逻辑删除 DbUpdate ud = new DbUpdate(); entityFieldFillExecutor.fillLogicalDeleteDataState(ud); if (fillUpdateParams) { entityFieldFillExecutor.fillLogicalDeleteParams(ud); } SqlBuffer buffer = sqlHelper().buildUpdateSql(ud, readyWhere, ValidStrategy.AUTO); if (buffer.isBlank()) { rows = 0; log.debug("Update set fields is empty, the logical delete operation will be skipped."); } else { rows = jdbc.update(buffer); } } else { // 不支持逻辑删除 String details = "UnsupportedLogicDelete, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_UNSUPPORTED_LOGICAL_DELETE).setDetails(details); } } if (rows == 0 && errorOnUnaffected) { throw new ServiceException(DbErrorCode.DB_AFFECTED_ROWS_IS_ZERO); } return rows; } /** * 执行实体业务数据转换及创建参数填充
* 作为以下两个方法的入口, 参数只支持map和T两种:
* fillEntityCreateParams(Map, boolean)/convertEntityAndFillCreateParams(T, boolean)
* * @param object 实体对象, 只支持map和T两种 * @param fillCreateParams 是否自动填充创建参数 * @return 实体类转换后的map和自动填充的主键ID */ protected PkEntity convertAndFillCreateParams(Object object, boolean fillCreateParams) { if (object == null) { String details = "CanNotExecuteCreate, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details); } if (object instanceof PkEntity) { PkEntity pe = (PkEntity) object; Map entity = pe.getEntity(); SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey(); // 如果PkEntity里面的id不为空, 设置到entity中 if (pk != null && VerifyTools.isNotBlank(pe.getPrimaryKey())) { entity.put(pk.getFieldName(), pe.getPrimaryKey()); } if (entity.isEmpty()) { String details = "NoFieldsThatBeInsertedWereFound, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details); } // 填充主键/数据状态/创建人/创建时间等信息 fillEntityCreateParams(entity, fillCreateParams); return pe; } else if (object instanceof Map) { @SuppressWarnings("unchecked") Map entity = (Map) object; if (entity.isEmpty()) { String details = "NoFieldsThatBeInsertedWereFound, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details); } String id = fillEntityCreateParams(entity, fillCreateParams); return new PkEntity(id, entity); } else if (beanClass.isAssignableFrom(object.getClass())) { @SuppressWarnings("unchecked") T entity = (T) object; return convertEntityAndFillCreateParams(entity, fillCreateParams); } else { String details = "CanNotExecuteCreate, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_UNSUPPORTED_ENTITY_TYPE).setDetails(details); } } /** * 执行实体业务数据创建参数填充
* 1. 查找主键ID, 如果有主键字段且字段值为空, 就自动生成ID
* 2. 填充创建参数中的数据状态
* 3. 如果fillCreateParams=true, 则填充其他创建参数 * * @param entity 实体对象 * @param fillCreateParams 是否自动填充创建参数 * @return 填充或获取的主键ID */ protected String fillEntityCreateParams(Map entity, boolean fillCreateParams) { String tableName = sqlHelper().fragment().getTableName(); // 查找主键 String id; SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey(); if (pk == null) { id = null; } else if (VerifyTools.isNotBlank(entity.get(pk.getFieldName()))) { Object pkValue = SqlTools.unwrapDbVariable(entity.get(pk.getFieldName())); id = pkValue.toString(); } else { // 生成主键 entity.put(pk.getFieldName(), id = entityFieldFillExecutor.generatePrimaryKeyCode(tableName)); } entityFieldFillExecutor.fillEntityCreateDataState(entity); if (fillCreateParams) { entityFieldFillExecutor.fillEntityCreateParams(entity); } return id; } /** * 执行实体业务数据转换及创建参数填充
* 这里存在一个问题, 执行fillEntityCreateParams之后, 入参entity中的字段得不到更新
* 因此, 执行fillEntityCreateParams之前先记录下所有字段值原值
* 执行完fillEntityCreateParams之后比对字段差异, 将差异部分设置回入参entity中
* 比对差异是为了提升性能, 因为对entity操作需要用到反射, 而比对差异只是对map操作, 快很多
* 例如一个类有20个字段, fillEntityCreateParams只修改了2个, 比对差异可以避免对其他18个字段的反射操作
* * @param entity 实体对象 * @param fillCreateParams 是否自动填充创建参数 * @return 实体类转换后的map和自动填充的主键ID */ protected PkEntity convertEntityAndFillCreateParams(T entity, boolean fillCreateParams) { // 将对象转换为map DbConditionConverter conditionConverter = jdbc.plugins().getDbConditionConverter(); Map readyEntity = conditionConverter.convertBeanToInsertMap(entity); if (readyEntity.isEmpty()) { String details = "NoFieldsThatBeInsertedWereFound, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details); } // 记录下所有字段值原值, 用于比较差异 Map original = new HashMap<>(readyEntity); // 填充主键/数据状态/创建人/创建时间等信息 String id = fillEntityCreateParams(readyEntity, fillCreateParams); // 比对修改后的字段值与原值的差异, 复制到原对象 Map diff = copmareMapDifference(original, readyEntity); MapToBeanConverter mapToBeanConverter = jdbc.plugins().getMapToBeanConverter(); mapToBeanConverter.fillTo(diff, entity); return new PkEntity(id, readyEntity); } /** * 执行实体业务数据转换及更新参数填充 * * @param object 实体对象, 只支持map/T/PkEntity, 其他类型将会报错
* 如果object是map, map中不能有where, 如果有,调这个方法之前要移除, 否则将会报错 * @param fillUpdateParams 是否自动填充更新参数 * @return 转换后的update和where */ protected PkEntity convertAndFillUpdateParams(Object object, boolean fillUpdateParams) { if (object == null) { String details = "CanNotExecuteUpdate, EntityIsNull, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details); } // 查找主键 SimpleFieldColumn pk = sqlHelper().fragment().getPrimaryKey(); if (pk == null) { // 没有找到主键字段 String details = "UnsupportedBatchUpdate, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED).setDetails(details); } if (object instanceof PkEntity) { PkEntity pe = (PkEntity) object; Serializable pkValue = pe.getPrimaryKey(); // 主键值不能为空 if (VerifyTools.isBlank(pkValue)) { // 主键值为空 String details = "CanNotExecuteUpdateById, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED).setDetails(details); } Map entity = pe.getEntity(); // 检查UpdateEntity checkUpdateEntity(entity); // 填充实体的修改参数(如修改人修改时间等) fillEntityUpdateParams(entity, fillUpdateParams); return pe; } else if (object instanceof Map) { @SuppressWarnings("unchecked") Map entity = (Map) object; // 检查UpdateEntity checkUpdateEntity(entity); Object pkValue = entity.get(pk.getFieldName()); // 主键值不能为空 if (VerifyTools.isBlank(pkValue)) { // 主键值为空 String details = "CanNotExecuteUpdateById, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED).setDetails(details); } // 填充实体的修改参数(如修改人修改时间等) fillEntityUpdateParams(entity, fillUpdateParams); return new PkEntity(SqlTools.unwrapDbVariable(pkValue).toString(), entity); } else if (beanClass.isAssignableFrom(object.getClass())) { @SuppressWarnings("unchecked") T entity = (T) object; Map map = convertEntityAndFillUpdateParams(entity, fillUpdateParams); Object pkValue = map.get(pk.getFieldName()); // 主键值不能为空 if (VerifyTools.isBlank(pkValue)) { // 主键值为空 String details = "CanNotExecuteUpdateById, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_VALUE_IS_REQUIRED).setDetails(details); } return new PkEntity(pkValue.toString(), map); } else { String details = "CanNotExecuteUpdate, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_UNSUPPORTED_ENTITY_TYPE).setDetails(details); } } private void checkUpdateEntity(Map entity) { if (entity == null || entity.isEmpty()) { String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details); } if (entity.containsKey("where")) { // entity里面不能有where, 如果有,调这个方法之前要移除, 否则将会报错 // 因为批量更新的语法不支持每个ID带有不同的where条件 String details = "Unsupported entity.where"; throw new ServiceException(ResultCode.PARAMETER_VALUE_ERROR).setDetails(details); } } /** * 执行实体业务数据更新参数填充 * * @param entity 实体对象 * @param fillUpdateParams 是否自动填充创建参数 */ protected void fillEntityUpdateParams(Map entity, boolean fillUpdateParams) { // 不需要自动填充修改时的数据状态标记, 没有这样的业务场景 // entityFieldFillExecutor.fillEntityUpdateDataState(entity); if (fillUpdateParams) { // 填充单表修改参数(如修改人修改时间等) entityFieldFillExecutor.fillEntityUpdateParams(entity); } } /** * 执行实体业务数据更新参数填充 * * @param ud 待更新的内容 * @param fillUpdateParams 是否自动填充创建参数 */ protected void fillEntityUpdateParams(DbUpdate ud, boolean fillUpdateParams) { // 不需要自动填充修改时的数据状态标记, 没有这样的业务场景 // entityFieldFillExecutor.fillEntityUpdateDataState(ud); if (fillUpdateParams) { // 填充单表修改参数(如修改人修改时间等) entityFieldFillExecutor.fillEntityUpdateParams(ud); } } /** * 执行实体业务数据创建参数填充
* 这里存在一个问题, 执行fillEntityUpdateParams之后, 入参entity中的字段得不到更新
* 因此, 执行fillEntityUpdateParams之前先记录下所有字段值原值
* 执行完fillEntityUpdateParams之后比对字段差异, 将差异部分设置回入参entity中
* 比对差异是为了提升性能, 因为对entity操作需要用到反射, 而比对差异只是对map操作, 快很多
* 例如一个类有20个字段, fillEntityUpdateParams只修改了2个, 比对差异可以避免对其他18个字段的反射操作
* * @param entity 实体对象 * @param fillUpdateParams 是否自动填充更新参数 * @return 实体类转换后的map */ protected Map convertEntityAndFillUpdateParams(T entity, boolean fillUpdateParams) { // 将对象转换为map DbConditionConverter conditionConverter = jdbc.plugins().getDbConditionConverter(); Map readyEntity = conditionConverter.convertBeanToUpdateMap(entity); if (readyEntity.isEmpty()) { String details = "NoFieldsThatBeUpdatedWereFound, class=" + beanClass.getName(); throw new ServiceException(DbErrorCode.DB_ENTITY_MUST_NOT_BE_EMPTY).setDetails(details); } // 记录下所有字段值原值, 用于比较差异 Map original = new HashMap<>(readyEntity); // 填充主键/数据状态/创建人/创建时间等信息 fillEntityUpdateParams(readyEntity, fillUpdateParams); // 比对修改后的字段值与原值的差异, 复制到原对象 Map diff = copmareMapDifference(original, readyEntity); MapToBeanConverter mapToBeanConverter = jdbc.plugins().getMapToBeanConverter(); mapToBeanConverter.fillTo(diff, entity); return readyEntity; } /** 获取当前实例的Bean类型 **/ @Override public Class getBeanClass() { return beanClass; } /** 批量执行时的大小限制(0为无限制) **/ protected int getDefaultBatchSize() { return defaultBatchSize; } /** 批量执行时的大小限制(0为无限制) **/ protected void setDefaultBatchSize(int batchSize) { this.defaultBatchSize = batchSize; } private static class CrudSqlOperator implements SqlOperator { private final SqlBoot sqlBoot; private final CrudSqlHelper sqlHelper; public CrudSqlOperator(Class beanClass, SqlBoot sqlBoot) { this.sqlBoot = sqlBoot; this.sqlHelper = sqlBoot.sqlHelper(beanClass); } @Override public SqlBuffer newSqlBuffer() { return sqlBoot.newSqlBuffer(); } @Override public SqlBuilder newSqlBuilder() { return sqlBoot.newSqlBuilder(); } @Override public ParseTools parseTools() { return sqlBoot.parseTools(); } @Override public CommonSqlTools sqlTools() { return sqlBoot.sqlTools(); } @Override public CrudSqlHelper sqlHelper() { return sqlHelper; } @Override public SqlFragmentContainer sqlContainer() { return sqlBoot.sqlContainer(); } @Override public SqlDialect sqlDialect() { return sqlBoot.sqlDialect(); } @Override public DbPluginHelper plugins() { return sqlBoot.plugins(); } } }