使用deepCopy复制实体触发am_location表key_列非空约束异常,是否需自定义实现?
问题背景
界面中“复制”按钮的代码实现:
public void execute() { BaseUuidEntity entity = (BaseUuidEntity) metadata.getTools().deepCopy(target.getSingleSelected()); entity.setId(UUID.randomUUID()); screenBuilders.editor(target) .newEntity(entity) .build() .show(); }
平台内置的deepCopy()方法:
public <T extends Entity> T deepCopy(T source) { CachingEntitiesHolder entityFinder = new CachingEntitiesHolder(); Entity destination = entityFinder.create(source.getClass(), source.getId()); deepCopy(source, destination, entityFinder); return (T) destination; }
使用deepCopy()复制“主仓库”实体时,出现数据库错误:am_location关联表的key_列存在NULL值,违反NOT NULL约束。调试发现对应实体的refLocation属性被复制为null,而Location表的KEY字段设置了非空约束,导致复制后的实体无法保存。
尝试替换为copy()方法,但触发了未获取属性的IllegalStateException,且我的实体包含大量嵌套集合,copy()无法满足需求,只有deepCopy()符合场景但表现异常。
可行的解决方案
1. 先排查关联属性的加载状态
平台deepCopy()复制关联实体时,如果源实体的关联属性未被加载(比如延迟加载的关联对象),复制后就会出现null值。先确认:
- 复制前是否已通过
dataManager.load()或视图配置,加载了源实体的refLocation属性 - 示例代码:
BaseUuidEntity source = target.getSingleSelected(); // 用包含关联属性的视图加载源实体 source = dataManager.load(source.getId()).view("warehouse-with-refLocation").one();
2. 复制后手动补全非空属性
如果平台复制逻辑确实遗漏了非空字段,可以在deepCopy()之后手动修复:
public void execute() { BaseUuidEntity source = target.getSingleSelected(); // 确保关联属性已加载 source = dataManager.load(source.getId()).view("warehouse-with-refLocation").one(); BaseUuidEntity copiedEntity = (BaseUuidEntity) metadata.getTools().deepCopy(source); // 补全非空的refLocation属性 if (copiedEntity instanceof WarehouseEntity) { WarehouseEntity warehouse = (WarehouseEntity) copiedEntity; if (warehouse.getRefLocation() == null) { warehouse.setRefLocation(source.getRefLocation()); } } copiedEntity.setId(UUID.randomUUID()); screenBuilders.editor(target) .newEntity(copiedEntity) .build() .show(); }
3. 扩展平台的deepCopy()方法
如果多个实体都存在类似问题,可以继承平台的实体工具类,重写deepCopy()方法统一处理非空字段:
public class CustomEntityTools extends EntityTools { @Override public <T extends Entity> T deepCopy(T source) { T copied = super.deepCopy(source); // 针对WarehouseEntity处理非空字段 if (copied instanceof WarehouseEntity) { WarehouseEntity warehouse = (WarehouseEntity) copied; if (warehouse.getRefLocation() == null && source instanceof WarehouseEntity) { warehouse.setRefLocation(((WarehouseEntity) source).getRefLocation()); } } // 其他实体的处理逻辑... return copied; } }
然后在项目中替换使用自定义的工具类。
4. 仅针对异常实体编写自定义复制逻辑
如果只有少数实体出问题,可以单独为这些实体编写复制方法,复用平台的嵌套集合复制能力:
private WarehouseEntity copyWarehouse(WarehouseEntity source) { // 用平台deepCopy处理嵌套集合 WarehouseEntity copied = metadata.getTools().deepCopy(source); // 修复非空字段 copied.setRefLocation(source.getRefLocation()); copied.setId(UUID.randomUUID()); return copied; }
5. 检查实体映射与数据库约束的一致性
确认实体类中refLocation属性是否添加了@NotNull注解,数据库表的非空约束是否和实体配置一致。映射配置错误也可能导致复制时属性丢失。
结论
不需要立刻完全自行实现复制方法,优先尝试确保关联属性加载和复制后手动补全字段的方案,这样能最大程度复用平台的嵌套集合复制逻辑。只有当平台复制逻辑存在多处无法修复的缺陷时,再考虑完全自定义复制方法。
内容的提问来源于stack exchange,提问作者SanyaKirilloff

