解决mybatisplus MetaObjectHandler 失效的问题
作者:lilun1231
一、什么是metaObjectHandler
MetaObjectHandler接口是mybatisPlus为我们提供的的一个扩展接口,我们可以利用这个接口在我们插入或者更新数据的时候,为一些字段指定默认值
使用方式如下:
1、在实体类上加入@TableField注解
@Getter @Setter public class AbstractBaseDO<T extends Model<T>> extends Model<T> implements Serializable { /** * 创建时间 新增时填充 */ @TableField(fill = FieldFill.INSERT) private Date gmtCreate; /** * 修改时间 新增和更新时填充 */ @TableField(fill = FieldFill.INSERT_UPDATE) private Date gmtModified; /** * 创建人ID 新增时更新 */ @TableField(fill = FieldFill.INSERT) private Long creatorId; /** * 修改人ID 新增和更新时填充 */ @TableField(fill = FieldFill.INSERT_UPDATE) private Long modifierId; /** * 逻辑删除字段 新增和更新时填充 */ @TableField(fill = FieldFill.INSERT_UPDATE) private Integer isDeleted; @Override public String toString() { return new ToStringBuilder(this) .append("gmtCreate", gmtCreate) .append("gmtModified", gmtModified) .append("creatorId", creatorId) .append("modifierId", modifierId) .append("isDeleted", isDeleted) .toString(); } }
2、创建配置类实现MetaObjectHandler接口
@Slf4j @Configuration public class MetaObjectHandlerConfig implements MetaObjectHandler { /** *插入时自动填充 */ @Override public void insertFill(MetaObject metaObject) { //获得用户上下文 UserContext dscUser = GlobalSessionContext.getDscUser(); //获得当前时间 Date date = Calendar.getInstance().getTime(); //创建时间 this.fillStrategy(metaObject, "gmtCreate", date); //更新时间 this.fillStrategy(metaObject, "gmtModified", date); //未删除 this.fillStrategy(metaObject, "isDeleted", CommonConstants.NON_DELETED); //创建者 this.fillStrategy(metaObject, "creatorId", dscUser.getUserId()); //更新者 this.fillStrategy(metaObject, "modifierId", dscUser.getUserId()); } /** *修改时自动填充 */ @Override public void updateFill(MetaObject metaObject) { //获得用户上下文 UserContext dscUser = GlobalSessionContext.getDscUser(); //获得当前时间 Date date = Calendar.getInstance().getTime(); //强制更新时间 this.setFieldValByName("gmtModified", date, metaObject); //更新者 this.fillStrategy(metaObject, "modifierId",dscUser.getUserId()); } }
二、失效场景及解决方案
1、使用mybatis-plus的boolean update(Wrapper updateWrapper)链式更新方法时失效
1)示例代码
/** *更新属性 */ @Override public Boolean expireHistoryTask(Long tenantId, Long produceInfoId) { return this.update(new UpdateWrapper<TaskDetailInfoDO>().lambda() .eq(TaskDetailInfoDO::getTenantId, tenantId) .in(TaskDetailInfoDO::getProduceInfoId, produceInfoId) .eq(TaskDetailInfoDO::getIsDeleted, CommonConstants.NON_DELETED) .set(TaskDetailInfoDO::getTaskStatus, TaskStatusEnum.EXPIRED.getCode()) }
2)失效原因
这种更新方法失效我们需要去看mbatis-plus的源码
private static void process(MappedStatement ms, Object parameterObject) { if (parameterObject != null) { TableInfo tableInfo = null; Object entity = parameterObject; if (parameterObject instanceof Map) { Map<?, ?> map = (Map<?, ?>) parameterObject; if (map.containsKey(Constants.ENTITY)) { Object et = map.get(Constants.ENTITY); if (et != null) { entity = et; tableInfo = TableInfoHelper.getTableInfo(entity.getClass()); } } } else { tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass()); } //tableInfo为空,则不自动填充 if (tableInfo != null) { //到这里就应该转换到实体参数对象了,因为填充和ID处理都是争对实体对象处理的,不用传递原参数对象下去. MetaObject metaObject = ms.getConfiguration().newMetaObject(entity); if (SqlCommandType.INSERT == ms.getSqlCommandType()) { populateKeys(tableInfo, metaObject, entity); insertFill(metaObject, tableInfo); } else { updateFill(metaObject, tableInfo); } } } }
从上面的代码可以看出,当tableInfo为空,则不自动填充字段值。而继续看,tableInfo是从parameterObject中获取,而这parameterObject就是要更新的实体对象。
在看我们使用 update(Wrapper updateWrapper)更新的底层逻辑
/** * 根据 UpdateWrapper 条件,更新记录 需要设置sqlset * * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper} */ default boolean update(Wrapper<T> updateWrapper) { //传入了一个空实体 return update(null, updateWrapper); }
此时是传了一个空对象,这就导致了整个后续的填充都失效了。
3)解决方法
使用update的另一个方法
在更新是传入实体对象
@Override public Boolean expireHistoryTask(Long tenantId, Long produceInfoId) { return this.update(new TaskDetailInfoDO(), new UpdateWrapper<TaskDetailInfoDO>().lambda() .eq(TaskDetailInfoDO::getTenantId, tenantId) .in(TaskDetailInfoDO::getProduceInfoId, produceInfoId) .eq(TaskDetailInfoDO::getIsDeleted, CommonConstants.NON_DELETED) .set(TaskDetailInfoDO::getTaskStatus, TaskStatusEnum.EXPIRED.getCode()) ); }
2、填充时使用 MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) 方法
@Override public void updateFill(MetaObject metaObject) { //获得用户上下文 UserContext dscUser = GlobalSessionContext.getDscUser(); //更新者 this.fillStrategy(metaObject, "modifierId", dscUser.getUserId()); }
fillStartegy的源码时这样的
/** * 填充策略,默认有值不覆盖,如果提供的值为null也不填充 * * @param metaObject metaObject meta object parameter * @param fieldName java bean property name * @param fieldVal java bean property value of Supplier * @since 3.3.0 */ default MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) { if (getFieldValByName(fieldName, metaObject) == null) { setFieldValByName(fieldName, fieldVal, metaObject); } return this; }
当需要更新的字段已经有值时,则默认不更新。需要强制更新字段时,使用 MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) 方法更新字段值。
@Override public void updateFill(MetaObject metaObject) { //获得用户上下文 UserContext dscUser = GlobalSessionContext.getDscUser(); //获得当前时间 Date date = Calendar.getInstance().getTime(); //更新时间 this.setFieldValByName("gmtModified", date, metaObject); //更新者 this.setFieldValByName("modifierId", metaObject, dscUser.getUserId()); }
到此这篇关于解决mybatisplus MetaObjectHandler 失效的问题的文章就介绍到这了,更多相关mybatisplus MetaObjectHandler 失效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!