Hibernate中@OneToMany的mappedBy关联继承抽象类问题
问题解决方案
报错原因
Hibernate解析Section的children集合时,由于集合泛型是抽象类Container,它会尝试在Container类中查找mappedBy指定的parentContainer属性,但你的Container未定义该属性,因此抛出关联异常。
可行方案(无需在Container中定义parentContainer)
因为你不想在父类Container中统一定义parentContainer,可以通过以下两种方式调整映射:
方案一:拆分集合,维护子类专属双向关联
将Section的children拆分为两个分别对应Section和Component的集合,各自通过mappedBy关联到子类的parentContainer,再通过方法合并为统一的Container集合:
@Entity @Table @PrimaryKeyJoinColumn(name = "id") public class Section extends Container { @ManyToOne @JoinColumn(name = "id_parent_section") private Section parentContainer; // 关联子Section,对应Section类的parentContainer @OneToMany(mappedBy = "parentContainer") private Set<Section> childSections = new HashSet<>(); // 关联子Component,对应Component类的parentContainer @OneToMany(mappedBy = "parentContainer") private Set<Component> childComponents = new HashSet<>(); // 对外提供统一获取所有子容器的方法 public Set<Container> getChildren() { Set<Container> allChildren = new HashSet<>(); allChildren.addAll(childSections); allChildren.addAll(childComponents); return allChildren; } // 手动维护双向关联的添加方法 public void addChild(Container child) { if (child instanceof Section) { Section sectionChild = (Section) child; childSections.add(sectionChild); sectionChild.setParentContainer(this); } else if (child instanceof Component) { Component componentChild = (Component) child; childComponents.add(componentChild); componentChild.setParentContainer(this); } } // 省略其他getter/setter及删除方法 }
这种方式保留了双向关联的完整性,Hibernate能正确识别每个集合对应的子类属性,同时对外提供统一的子容器访问入口。
方案二:使用@ManyToAny实现多类型单向关联
如果不想拆分集合,可借助Hibernate的@ManyToAny注解,通过中间表维护Section与所有Container子类的关联:
@Entity @Table @PrimaryKeyJoinColumn(name = "id") public class Section extends Container { @ManyToOne @JoinColumn(name = "id_parent_section") private Section parentContainer; @ManyToAny @AnyMetaDef( idType = "long", // 对应Container的ID类型 metaType = "string", // 用于区分子类的元数据类型 metaValues = { @MetaValue(targetEntity = Section.class, value = "SECTION"), @MetaValue(targetEntity = Component.class, value = "COMPONENT") } ) @JoinTable( name = "section_container_rel", // 中间表名称 joinColumns = @JoinColumn(name = "section_id"), // 关联当前Section的ID inverseJoinColumns = @JoinColumn(name = "container_id") // 关联子Container的ID ) private Set<Container> children = new HashSet<>(); // 省略getter/setter }
这种方式无需修改子类结构,但会失去双向关联的自动维护能力(若需从子节点反向查询父Section,需手动实现),且需要额外创建中间表。
内容的提问来源于stack exchange,提问作者edit2112
相关产品推荐
相关产品推荐

