使用Orika实现双向OneToMany下DTO转JPA实体外键为空如何解决
解决方案
方案1:重写Parent实体的setChilds方法(最简便)
直接在Parent实体类中重写childs属性的setter方法,Orika映射集合时会自动调用该方法,在赋值的同时完成子实体父引用的同步,无需修改映射配置和业务代码:
public void setChilds(List<Child> childs) { this.childs = childs; if (childs != null) { childs.forEach(child -> child.setParent(this)); } }
方案2:使用Orika后置映射钩子(无实体侵入)
如果不想修改实体类,可以在Orika的映射规则中添加全局后置处理逻辑,该配置仅需注册一次,所有ParentDto到Parent的映射都会自动执行同步逻辑,业务代码无需调整:
factory.classMap(ParentDto.class, Parent.class) .byDefault() .customize(new CustomMapper<ParentDto, Parent>() { @Override public void afterMapping(ParentDto source, Parent destination, MappingContext context) { if (destination.getChilds() != null) { destination.getChilds().forEach(child -> child.setParent(destination)); } } }) .register();
方案3:改用单向OneToMany关联
确实可以解决该问题,修改方式如下:
- 去掉
Child实体中的parent属性及对应的@ManyToOne注解 - 修改
Parent实体的@OneToMany配置,删除mappedBy参数,添加@JoinColumn注解:
@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true) @JoinColumn(name = "parent_id") private List<Child> childs;
该方案下JPA会直接维护子表的外键字段,无需处理子实体的父引用,但弊端是无法从子实体侧直接查询关联的父实体,仅适合不需要反向查询的业务场景。
关于性能的说明
遍历子列表设置父引用的开销远低于JPA持久化本身的IO开销,完全不需要担心性能问题,上述三个方案都可以避免在业务代码中重复编写样板遍历逻辑,符合你使用映射框架的初衷。
内容的提问来源于stack exchange,提问作者springenthusiast
相关产品推荐
相关产品推荐

