• 集成 mybatisplus-plus时,联合主键中带“id”字段报错问题


    问题描述

    当集成mybatisplus-plus

    <dependency>
      <groupId>com.github.jeffreyning</groupId>
      <artifactId>mybatisplus-plus</artifactId>
      <version>1.5.1-RELEASE</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    且联合主键中有一个字段名称为“id”时

    @MppMultiId
    @TableField
    private String id;
    @MppMultiId
    @TableField
    private String roleId;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    调用selectByMultiId方法时会报错:

    java.lang.RuntimeException: not found column for id
    com.github.jeffreyning.mybatisplus.base.SelectByMultiIdMethod.getCol(SelectByMultiIdMethod.java:32)
    com.github.jeffreyning.mybatisplus.base.SelectByMultiIdMethod.createWhere(SelectByMultiIdMethod.java:42)
    com.github.jeffreyning.mybatisplus.base.SelectByMultiIdMethod.injectMappedStatement(SelectByMultiIdMethod.java:64)
    com.baomidou.mybatisplus.core.injector.AbstractMethod.inject(AbstractMethod.java:67)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    原因分析

    1. 当实体类没有设置“TableId”注解时,TableInfoHelper类在构造TableInfo时会自动将属性名称为“id”的字段设置为主键字段,不会添加到TableInfo的fieldList中
    //com/baomidou/mybatisplus/core/metadata/TableInfoHelper.class
    private static boolean initTableIdWithoutAnnotation(DbConfig dbConfig, TableInfo tableInfo, Field field) {
            String property = field.getName();
            if ("id".equalsIgnoreCase(property)) {  // 对id字段做特殊处理
                if (field.getAnnotation(TableField.class) != null) {
                    logger.warn(String.format("This \"%s\" is the table primary key by default name for `id` in Class: \"%s\",So @TableField will not work!", property, tableInfo.getEntityType().getName()));
                }
    
                String column = property;
                if (dbConfig.isCapitalMode()) {
                    column = property.toUpperCase();
                }
    
                Class<?> keyType = tableInfo.getReflector().getGetterType(property);
                if (keyType.isPrimitive()) {
                    logger.warn(String.format("This primary key of \"%s\" is primitive !不建议如此请使用包装类 in Class: \"%s\"", property, tableInfo.getEntityType().getName()));
                }
    
                tableInfo.setKeyRelated(checkRelated(tableInfo.isUnderCamel(), property, column)).setIdType(dbConfig.getIdType()).setKeyColumn(column).setKeyProperty(property).setKeyType(keyType);
                return true;
            } else {
                return false;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    1. 再SelectByMultiIdMethod的处理中,会从FieldList中查字段信息,自然就查询到不到id字段,所以就会报错
    // com/github/jeffreyning/mybatisplus/base/SelectByMultiIdMethod
    private String createWhere(Class<?> modelClass, TableInfo tableInfo) {
            List<TableFieldInfo> fieldList = tableInfo.getFieldList();
            Field[] fieldArray = modelClass.getDeclaredFields();
            Map<String, String> idMap = new HashMap();
            Field[] var6 = fieldArray;
            int var7 = fieldArray.length;
    
            for(int var8 = 0; var8 < var7; ++var8) {
                Field field = var6[var8];
                MppMultiId mppMultiId = (MppMultiId)field.getAnnotation(MppMultiId.class);
                if (mppMultiId != null) {
                    String attrName = field.getName();
                    String colName = this.getCol(fieldList, attrName); // 从FieldList中查字段
                    idMap.put(attrName, colName);
                }
            }
    
            if (idMap.isEmpty()) {
                logger.info("entity {} not contain MppMultiId anno", modelClass.getName());
                return null;
            } else {
                StringBuilder sb = new StringBuilder("");
                idMap.forEach((attrNamex, colNamex) -> {
                    if (sb.length() > 0) {
                        sb.append(" and ");
                    }
    
                    sb.append(colNamex).append("=").append("#{").append(attrNamex).append("}");
                });
                return sb.toString();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    解决方案

    方案1:实体类的联合主键字段不要使用“Id”,换成其他的

    @MppMultiId
    @TableField("id") // 属性名换掉,指定数据表列名
    private String userId;
    @MppMultiId
    @TableField
    private String roleId;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    方案2:在无法修改实体类(实例类自动生成出来的)情况下则需要重写TableInfoHelper类,考虑MppMultiId的情况:

    ​ 属性名称为“id” 且没有MppMultiId注解 且 实体类上没有TableId注解 ,才将id设置为主键 .

    private static boolean initTableIdWithoutAnnotation(DbConfig dbConfig, TableInfo tableInfo, Field field) {
      String property = field.getName();
      // 属性名称为“id” 且没有MppMultiId注解  且 实体类上没有TableId注解 ,才将id设置为主键 .
      if ("id".equalsIgnoreCase(property) && field.getAnnotation(MppMultiId.class) == null) {
        if (field.getAnnotation(TableField.class) != null) {
          logger.warn(String.format("This \"%s\" is the table primary key by default name for `id` in Class: \"%s\",So @TableField will not work!", property, tableInfo.getEntityType().getName()));
        }
    
        String column = property;
        if (dbConfig.isCapitalMode()) {
          column = property.toUpperCase();
        }
    
        Class<?> keyType = tableInfo.getReflector().getGetterType(property);
        if (keyType.isPrimitive()) {
          logger.warn(String.format("This primary key of \"%s\" is primitive !不建议如此请使用包装类 in Class: \"%s\"", property, tableInfo.getEntityType().getName()));
        }
    
        tableInfo.setKeyRelated(checkRelated(tableInfo.isUnderCamel(), property, column)).setIdType(dbConfig.getIdType()).setKeyColumn(column).setKeyProperty(property).setKeyType(keyType);
        return true;
      } else {
        return false;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    Pandas数据分析系列9-数据透视与行列转换
    【元胞自动机】基于元胞自动机模拟SEIR传播模型附matlab代码
    three.js 纹理
    图解系统(五)——文件系统02
    第1章 Linux基础知识 -- 了解Linux历史和linux目录结构
    mysql 锁定解除
    【YOLOv8】 用YOLOv8实现数字式工业仪表智能读数(二)
    阿里云易立:云原生如何破解企业降本提效难题?
    java后端开发热部署工具Springloaded
    竞赛 题目:基于深度学习的手势识别实现
  • 原文地址:https://blog.csdn.net/shui878412/article/details/125617448