Hibernate外键与部分复合主键

17


我需要使用Hibernate,但不太确定如何解决这个问题。我有两个表格之间的1到n关联,就像这样:

-------
TABLE_A
-------
col_b (pk)
col_c (pk)
[其他字段]
------- TABLE_B ------- col_a (pk) col_b (pk) (fk TABLE_A.col_b) col_c (fk TABLE_A.col_c) [其他字段]

我该如何用Hibernate管理它?

我不知道如何声明一个包含主键部分的外键。

我的数据库模式是从Hibernate模型生成的。


3
如果你想避免使用Hibernate...可以使用组合主键。但如果你想生活更轻松,确保每个表都有一个单独的主键列。相信我,这场战斗不值得...它将在未来花费你很多时间。 - lance-java
这里有一个相当详细的答案:https://dev59.com/oHA65IYBdhLWcg3w4CwL#3588400 - leeor
对于一对多的映射,您不需要使用复合键。不使用复合键更容易管理这种情况。 - We are Borg
@leeor 这个答案对我的情况没有帮助。它只是关于如何定义复合键的。 - Jagger
https://stackoverflow.com/questions/47890019/hibernate-model你能否就这个问题提出建议? - Java Techie
显示剩余2条评论
2个回答

15

我已经找到了解决这个问题的两种方案。

第一种方法是一种变通方法,不像第二种方法那样简洁。

B实体的主键定义为包含col_acol_b和原本应该是主键的内容的组合键,并将原本应该成为主键的内容定义为唯一约束条件。缺点是col_c列并不是主键的概念部分。

@Entity
class A {
  @Id
  private int b;
  @Id
  private int c;
}

@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = { "a", "b" }) })
class B {
  @Id
  private int a;

  @Id
  @ManyToOne(optional = false)
  @JoinColumns(value = {
          @JoinColumn(name = "b", referencedColumnName = "b"),
          @JoinColumn(name = "c", referencedColumnName = "c") })
  private A entityA;
}

第二种方法使用@EmbeddedId@MapsId注解,完全实现了我一开始想要的目标。

@Entity
class A {
  @Id
  private int b;
  @Id
  private int c;
}

@Embeddable
class BKey {
  private int a;
  private int b;
}

@Entity
class B {
  @EmbeddedId
  private BKey primaryKey;

  @MapsId("b")
  @ManyToOne(optional = false)
  @JoinColumns(value = {
          @JoinColumn(name = "b", referencedColumnName = "b"),
          @JoinColumn(name = "c", referencedColumnName = "c") })
  private A entityA;
}

为了使上述代码正常工作,您还需要为所有上述类实现Serializable。 - Baimyrza Shamyr
2
我尝试了这种方式,但是出现了“在@MapsId映射中找不到列引用:c”的错误。有什么想法吗?TIA - Yuliban
这是运行时错误还是编译错误?你能把你的代码发布到某个地方,这样我就可以看一下了吗? - Jagger
两个属性是否可以拥有相同的MapsId?例如,如果存在一个名为“d”的属性,它也是两个键的一部分(与b相同),这种情况是否可行? - schoenk
@schoenk 也许可以尝试使用另一个 @MapsId("d") 注释,这样最终你将有两个注释:@MapsId("b")@MapsId("d") - Jagger
1
很遗憾,在同一属性上无法使用多个´@MapsId´注释。但是,我通过使用´@JoinFormula´而不是´@JoinColumn´来解决了我的用例中用于主键和外键的列的问题。 - schoenk

-1
Jagger的第二个解决方案是我的第一反应,使用@EmbededId和@MapsId。以下是另一种基于他的第二个解决方案的方法,但不使用@MapsId。
@Entity
class A {
  @Id
  private int b;
  @Id
  private int c;
}

@Embeddable
class BKey {
  private int a;
  private int b;
}

@Entity
class B {
  @EmbeddedId
  private BKey primaryKey;

  @ManyToOne(optional = false)
  @JoinColumns(value = {
          @JoinColumn(name = "b", referencedColumnName = "b", insertable= false, updatable= false),
          @JoinColumn(name = "c", referencedColumnName = "c") }, )
  private A entityA;
}

1
这段代码无法运行,会抛出一个异常 org.hibernate.AnnotationException: Mixing insertable and non insertable columns in a property is not allowed。这是一个Hibernate的bug - Jagger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接