1.查询
通过 字段匹配查询,并按照 时间排序
baseMapper.selectList(
new QueryWrapper<SupplyEntity>()
.lambda()
.eq(SupplyEntity::getCardId, cardBasicInfoVM.getId())
.orderByDesc(SupplyEntity::getCreateTime));
entryStatService.delete(
new QueryWrapper<CardEntryStat>()
.lambda()
.eq(CardEntryStat::getShareType, shareType)
3 update
cardGroupRefService.update(cardGroupREntity,
new QueryWrapper<CardGroupREntity>().lambda().eq(CardGroupREntity::getGroupId, groupId));
4 计算count
int count = this.selectCount(new QueryWrapper<SupplyEntity>().lambda()
.eq(SupplyEntity::getCardId,cardId)
.eq(SupplyEntity::getType,type));
遇到问题 BuilderException
错误日志如下:
Caused by: org.apache.ibatis.builder.BuilderException:
Error evaluating expression 'ew!=null and !ew.emptyOfWhere'.
Cause: org.apache.ibatis.ognl.OgnlException: emptyOfWhere [com.baomidou.mybatisplus.core.exceptions.MybatisPlusException:
该模式不能应用于非 baseMapper 的泛型 entity 之外的 entity!]
查询用到的实体类如下
猜测可能和父类有关系,父类只有一个 id 属性。
@TableName("group")
@Getter
@Setter
@NoArgsConstructor
public class GroupEntity extends SuperEntity<GroupEntity> {
private String userId;
private String name;
private String createBy;
//我们报错的删除方法
public boolean delete( String id ,String userId) {
// TODO: 2019/3/4 bug 删除报错
this.delete(new QueryWrapper<GroupEntity>().lambda()
.eq(GroupEntity::getId,id)
.eq(GroupEntity::getCreateBy, id)
return true;
经过测试 发现改动如下就OK 了
public boolean delete( String id ,String userId) {
this.delete(new QueryWrapper<GroupEntity>().lambda()
.eq(GroupEntity::getCreateBy, id)
.eq(GroupEntity::getId,id)
return true;
好神奇,那我们来分析下是什么原因呢?
通过报异常的位置定位到源码如下
@SuppressWarnings("serial")
public abstract class AbstractLambdaWrapper<T, This extends AbstractLambdaWrapper<T, This>>
extends AbstractWrapper<T, Property<T, ?>, This> implements Serializable {
private Map<String, String> columnMap = null;
private boolean initColumnMap = false;
@Override
protected String columnToString(Property<T, ?> column) {
return getColumn(LambdaUtils.resolve(column));
private String getColumn(SerializedLambda lambda) {
if (!initColumnMap) {
String entityClassName = lambda.getImplClass().replace("/", ".");
columnMap = LambdaUtils.getColumnMap(entityClassName);
if (CollectionUtils.isEmpty(columnMap)) {
throw new MybatisPlusException("该模式不能应用于非 baseMapper 的泛型 entity 之外的 entity!");
initColumnMap = true;
return Optional.ofNullable(columnMap.get(StringUtils.resolveFieldName(lambda.getImplMethodName())))
.orElseThrow(() -> new MybatisPlusException("该模式不能应用于非数据库字段!"));
可以看到 if (!initColumnMap) 这一行去判断有没有初始化 column map
如果没有初始化的话 会通过反射去找到 实体类的名称,
而我们 new 的 QueryWrapper中 第一个 eq 判断
.eq(GroupEntity::getCreateBy, id)
用到的字段是 id ,这个字段 id是父类SuperEntity的属性,所以反射时候拿到实体的类是 父类了。
导致了这个的bug。
如何规避这个bug呢?
if (!initColumnMap)
这个判断ColumnMap 一个查询只会初始一次,所以我们调换 查询条件,先去判断子类的属性,这样
就会反射为子类的实体,就可以执行成功了。
新的版本已经修复了此问题
private String getColumn(SerializedLambda lambda, boolean onlyColumn) {
String fieldName = StringUtils.resolveFieldName(lambda.getImplMethodName());
if (!initColumnMap || !columnMap.containsKey(fieldName.toUpperCase(Locale.ENGLISH))) {
String entityClassName = lambda.getImplClassName();
columnMap = LambdaUtils.getColumnMap(entityClassName);
Assert.notEmpty(columnMap, "cannot find column's cache for \"%s\", so you cannot used \"%s\"!",
entityClassName, typedThis.getClass());
initColumnMap = true;
return Optional.ofNullable(columnMap.get(fieldName.toUpperCase(Locale.ENGLISH)))
.map(onlyColumn ? ColumnCache::getColumn : ColumnCache::getColumnSelect)