mybatisplus无主键表insert出现Class must not null报错

项目中用到pgsql+mybatisplus

insert数据报错

在调试过程中发现:

走到审计代码

entityClass为null,
entityClass是取自tableInfo的值

找到设置tableInfo的clazz字段的地方

com.baomidou.mybatisplus.core.toolkit.TableInfoHelper有一个initTableInfo方法

	public synchronized static TableInfo initTableInfo(MapperBuilderAssistant builderAssistant, Class<?> clazz) {
		TableInfo tableInfo = TABLE_INFO_CACHE.get(clazz);
		if (tableInfo != null) {
			if (builderAssistant != null) {
				tableInfo.setConfigMark(builderAssistant.getConfiguration());
			}
			return tableInfo;
		}

		/* 没有获取到缓存信息,则初始化 */
		tableInfo = new TableInfo();
		GlobalConfig globalConfig;
		if (null != builderAssistant) {
			tableInfo.setCurrentNamespace(builderAssistant.getCurrentNamespace());
			tableInfo.setConfigMark(builderAssistant.getConfiguration());
			tableInfo.setUnderCamel(builderAssistant.getConfiguration().isMapUnderscoreToCamelCase());
			globalConfig = GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration());
		} else {
			// 兼容测试场景
			globalConfig = GlobalConfigUtils.defaults();
		}

		/* 初始化表名相关 */
		initTableName(clazz, globalConfig, tableInfo);

		/* 初始化字段相关 */
		initTableFields(clazz, globalConfig, tableInfo);

		/* 放入缓存 */
		TABLE_INFO_CACHE.put(clazz, tableInfo);

		/* 缓存 Lambda 映射关系 */
		LambdaUtils.createCache(clazz, tableInfo);
		return tableInfo;
	}

在初始化字段的时候,会通过是否有主键,如果有主键,会设置tableInfo的一些属性,而其中一个属性就是clazz,但是由于这张表没有设置主键,没有id字段,导致clazz属性为null

	/**
	 * <p>
	 * 初始化 表主键,表字段
	 * </p>
	 *
	 * @param clazz        实体类
	 * @param globalConfig 全局配置
	 * @param tableInfo    数据库表反射信息
	 */
	public static void initTableFields(Class<?> clazz, GlobalConfig globalConfig, TableInfo tableInfo) {
		/* 数据库全局配置 */
		GlobalConfig.DbConfig dbConfig = globalConfig.getDbConfig();
		List<Field> list = getAllFields(clazz);
		// 标记是否读取到主键
		boolean isReadPK = false;
		// 是否存在 @TableId 注解
		boolean existTableId = isExistTableId(list);
		boolean existId = isExistId(list);

		List<TableFieldInfo> fieldList = new ArrayList<>();
		for (Field field : list) {
			/*
			 * 主键ID 初始化
			 */
			if (!isReadPK) {
				if (existTableId) {
					isReadPK = initTableIdWithAnnotation(dbConfig, tableInfo, field, clazz);
				} else if (existId) {
					isReadPK = initIdWithAnnotation(dbConfig, tableInfo, field, clazz);
				} else {
					isReadPK = initTableIdWithoutAnnotation(dbConfig, tableInfo, field, clazz);
				}
				if (isReadPK) {
					continue;
				}
			}

			boolean existColumn = isExistColumn(field);


			/* 有 @TableField 注解的字段初始化 */
			if (initTableFieldWithAnnotation(dbConfig, tableInfo, fieldList, field, clazz)) {
				continue;
			}

			if (existColumn) {
                /* 获取注解属性,自定义字段 */
                Column column = field.getAnnotation(Column.class);
                String columnName = field.getName();
                if (StringUtils.isNotEmpty(column.name())) {
                    columnName = column.name();
                }
                initColumnFieldWithAnnotation(dbConfig, tableInfo, fieldList, field, clazz, columnName);
			} else {
                /* 无 @TableField/@Column 注解的字段初始化 */
			    initColumnFieldWithAnnotation(dbConfig, tableInfo, fieldList, field, clazz, field.getName());
            }

			/* 无 @TableField 注解的字段初始化 */
			//fieldList.add(new TableFieldInfo(dbConfig, tableInfo, field));
		}

		/* 检查逻辑删除字段只能有最多一个 */
		Assert.isTrue(fieldList.parallelStream().filter(TableFieldInfo::isLogicDelete).count() < 2L,
			String.format("annotation of @TableLogic can't more than one in class : %s.", clazz.getName()));

		/* 字段列表 */
		tableInfo.setFieldList(fieldList);

		/* 未发现主键注解,提示警告信息 */
		if (StringUtils.isEmpty(tableInfo.getKeyColumn())) {
			logger.warn(String.format("Warn: Could not find @TableId in Class: %s.", clazz.getName()));
		}
	}
	/**
	 * <p>
	 * 主键属性初始化
	 * </p>
	 *
	 * @param tableInfo 表信息
	 * @param field     字段
	 * @param clazz     实体类
	 * @return true 继续下一个属性判断,返回 continue;
	 */
	private static boolean initTableIdWithoutAnnotation(GlobalConfig.DbConfig dbConfig, TableInfo tableInfo,
		Field field, Class<?> clazz) {
		String column = field.getName();
		if (dbConfig.isCapitalMode()) {
			column = column.toUpperCase();
		}
		if (DEFAULT_ID_NAME.equalsIgnoreCase(column)) {//表中没有id字段,这里根本没执行
			if (StringUtils.isEmpty(tableInfo.getKeyColumn())) {
				tableInfo.setKeyRelated(checkRelated(tableInfo.isUnderCamel(), field.getName(), column))
					.setIdType(dbConfig.getIdType()).setKeyColumn(column).setKeyProperty(field.getName())
					.setClazz(field.getDeclaringClass());
				return true;
			} else {
				throwExceptionId(clazz);
			}
		}
		return false;
	}

解决办法:使用注解@TableId设置entity中的一个唯一性值为主键

 

### 回答1: mybatisplus联合主键指的是在数据库中,由多个字段联合组成的主键。在mybatisplus中,可以使用注解@TableId(type = IdType.INPUT)来设置联合主键,并在实体类中声明多个主键字段。 在使用mybatisplus联合主键时,需要注意以下几点: 1. 联合主键的字段不可重复:联合主键的多个字段都必须是唯一的,否则会出现主键重复的情况。 2. 自增主键设置:如果联合主键中包含自增主键,需要将@IdType设置为AUTO,并在实体类中声明对应的自增主键字段。 3. 主键值的生成方式:mybatisplus通过注解@TableId的value属性来指定联合主键的生成方式,包括UUID、ID_WORKER等多种方式。 4. 主键类型的指定:mybatisplus通过@TableId的type属性来指定主键类型,包括字符串、整型和长整型等多种类型。 总之,使用mybatisplus联合主键时需要考虑多个字段之间的关系和唯一性,同时还需要设置主键的生成方式和类型。在实际应用中,需要根据业务需求来选择合适的联合主键方案。 ### 回答2: Mybatisplus 是 Mybatis 的一个增强版本,它提供了许多方便的操作,在处理数据库的各种场景时都能够得到很好的支持。在处理联合主键的情况时,Mybatisplus 也提供了方便的API。 联合主键也叫复合主键,是指在一个中,主键由两个或多个字段组成。在这些字段的值都确定的情况下,才是唯一确定一条记录的依据。联合主键之间的关联中经常使用,比如在一张订单明细中,订单编号和商品编号联合组成了主键Mybatisplus 支持联合主键的操作,需要在实体类上指定多个主键。如下示例: ```java @Data @TableName(value = "user_role") public class UserRole { @TableId(value = "user_id") private Long userId; @TableId(value = "role_id") private Long roleId; } ``` 在注解 @TableId 中,value 值指定了字段名,这样就可以指定多个主键了。在进行联合主键的增删改查操作时,需要借助 Mybatisplus 提供的一些方法。 1. 增加操作 ```java userRoleMapper.insert(userRole); ``` 2. 删除操作 ```java Map<String, Object> columnMap = new HashMap<>(); columnMap.put("user_id", userId); columnMap.put("role_id", roleId); userRoleMapper.deleteByMap(columnMap); ``` 3. 更新操作 ```java userRoleMapper.update(userRole, updateWrapper); ``` 4. 查询操作 ```java Map<String, Object> columnMap = new HashMap<>(); columnMap.put("user_id", userId); columnMap.put("role_id", roleId); List<UserRole> userRoleList = userRoleMapper.selectByMap(columnMap); ``` Mybatisplus 的联合主键操作,就是通过指定实体类中多个主键来完成的,同时需要借助 Mybatisplus 提供的一些方法来实现增删改查的操作。联合主键之间关联中经常出现,使用 Mybatisplus 操作时,可以很方便地实现这些操作。 ### 回答3: Mybatisplus联合主键是指在数据库中,一个中的主键列不止一个,通常是由两列及以上的列组成。在Mybatisplus中,联合主键可以用于生成实体类的ID字段,也可以用于查询操作中的单个或多个的连查询。 Mybatisplus联合主键的设计需要注意以下几点: 1. 实体类中的联合主键需要使用@IdClass注解标识,并在该注解中指定对应的主键类,用于实现复合主键的映射。 2. 在实体类中,需要定义对应的字段,并使用@Column注解标识,标识该字段是主键中的一部分,并指定对应的字段名。 3. 在Mapper接口中,需要使用@SelectKey注解标识实体类的主键字段,并指定对应的SQL语句及SQL语句中各个参数的值。 4. 在Mapper接口中,需要定义对应的查询操作,这些查询操作可以是单查询,也可以是多关联查询,并使用@Select注解指定对应的SQL语句。 5. 在XML映射文件中,在<resultMap>节点中定义对应的主键字段,并使用<id>节点标识该字段是主键中的一部分,并指定对应的列名。 6. 在XML映射文件中,在<insert>节点中定义对应的主键字段,并使用<selectKey>节点标识该字段是主键中的一部分,并指定对应的SQL语句及各个参数的值。 7. 在XML映射文件中,在<select>节点中可以使用多关联查询,并定义对应的联合主键。 总之,Mybatisplus联合主键可以使得我们在实际开发中更加方便、快捷地实现数据库操作,提升开发效率,减少代码量。同时,联合主键的设计需要注意标识复合主键的注解、SQL语句设置及XML映射文件的配置等方面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值