休眠 - 使用包含父 ID 的复合键 - OneToMany

Posted

技术标签:

【中文标题】休眠 - 使用包含父 ID 的复合键 - OneToMany【英文标题】:Hibernate - using composite key that contains a parent id - OneToMany 【发布时间】:2016-12-27 17:34:20 【问题描述】:

(原问题已更改,请参阅下面的更新。)

我无法让 hibernate 设置子对象的主键。主键与父主键相同。

这是父母的样子:

@Entity
@Table(name = "PARENT")
@SequenceGenerator(name = "SEQ", allocationSize = 1, sequenceName = "seq_parent_id")
public class Parent 

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ")
    private Long id;

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Fetch(value = FetchMode.SUBSELECT)
    @JoinColumn(name = "PARENT_ID")
    private Set<Child> children;

这就是孩子的样子:

@Entity
@Table(name = "CHILDREN")
public class Child 

    @Id
    @Column(name = "PARENT_ID")
    private Long parentId;

现在,当我运行 JUnit 存储库测试并尝试将父实体与子实体一起保存时,出现异常:

org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): ...

让hibernate自动将 Child.parentId 设置为 parent.id 的正确方法是什么?

我试着给孩子一个父母。但是遇到了其他异常,因为 Parent 不是 Id。

更新

我意识到孩子的 ID 不是真正的主键。它只是一个映射键。 parent.id 可以有多个子条目。

更新

现在我开始意识到我真正需要的是什么:

孩子的主键是三个值的复合键:父 id 和另外两个 String 值。

@Entity
@Table(name = "CHILDREN")
public class Child 

    @Column(name = "PARENT_ID")
    private Long parentId;

    @Column(name = "PROPERTY_NAME")
    private String propertyName;

    @Column(name = "ANOTHER_PROPERTY")
    private String anotherProperty;

    @Column(name = "PROPERTY_VALUE")
    private String propertyValue;

所以我需要使用 parentId、properyName 和 anotherProperty 映射复合键。 propertyValue 是该条目的实际值。

我想我可能需要使用 IdClass 或 embeddedId。我试过了,但到目前为止没有成功。

【问题讨论】:

您应该在关系的另一端声明 JoinColumn。在Child 类中声明@ManyToOne 关系。但是IMO,你有一个设计问题:如果Parent 有多个ChildParent 怎么可能是Child 的主键? (多个Child 将具有相同的Parent,因此具有相同的主键)。 哦,你是对的。这不是真正的主键!!!只是一把钥匙!!该表没有真实 ID。 【参考方案1】:

这可能取决于您的预期语义,但如果子 PK 也是父级的 FK,那么我会假设它表示 IS-A 类型关系 - 或者,用数据库术语来说,该 CHILD 是一个扩展表家长。您可以将其设置为每个类的表继承。

更新

所以根据您的更新,Child 中的 ParentID 不是 Child 的 PK;这意味着它不应使用 @Id 进行注释,而应像任何其他 FK 一样设置。我会考虑不映射 ParentID,而是映射 Parent,虽然 YMMV。

然后一个单独的问题是,孩子的唯一 ID 是什么(如果有的话 - 尽管如果没有的话,您可能会遇到麻烦)是什么?它是独立分配的代理人吗?包含父 ID 的组合?或者是其他东西?所有这些情况都可以适应,但如果没有更多关于您需要哪些信息的信息,我可能无法详细说明每种可能性......

【讨论】:

不确定我是否理解正确,但我不会将其视为 Parent 表的扩展,因为 Parent 可以有很多孩子。 如果一个父节点可以有多个子节点,那么子表上的 PK 不能是父 PK 的 FK。 其实child的唯一键是一个复合键,包含三个值:parent的id和另外两个String值。

以上是关于休眠 - 使用包含父 ID 的复合键 - OneToMany的主要内容,如果未能解决你的问题,请参考以下文章

使用复合键(长,日期)选择最新的对象的休眠查询

在休眠中使用复合键

如何使用注释创建休眠复合键

没有复合键的休眠中的多对多

HibernateTemplate 复合键获取值 null

使用未映射的列映射复合键