JPA - 多个表之间共享主键的一对一关系

时间:2011-10-05 10:08:05

标签: orm annotations persistence jpa-2.0 shared-primary-key

考虑以下示例:

我有3张桌子:Fruit,Orange和Apple

id在水果表中生成,并且是此处的主键

id也是Orange和Apple(共享主键)的主键

因此,例如如果水果中的ID是1,2,3,4,5 - 那么情节可能是1,2,橙色是3,3是Apple,5是橙色..

所以Orange表的id为1,2,5,而Apple表的id为3,4,

=================================== 
 Fruit
===================================
 id     |   shape
===================================
  1     |   round
  2     |   round
  3     |   oblong
  4     |   oblong
  5     |   round
===================================


===================================
 Orange
===================================
 id     |   color    | taste
===================================
  1     |   orange   |  sour
  2     |   orange   |  sour
  5     |   orange   |  sour
===================================


===================================
 Apple
===================================
 id     |   density    | weight
===================================
  1     |   hard       |  200
  2     |   hard       |  220
  5     |   hard       |  230
===================================

问题:如何创建捕获关系的实体类,也只使用JPA注释(我不想使用hibernate generatedValue注释)。

如果使用纯JPA可以进行此类注释,那么请指导我。

的Nik

2 个答案:

答案 0 :(得分:2)

您的案例看起来像设计模式的一个实例,称为“泛化专业化”,或简称为Gen-Spec。如何使用数据库表对数组规范建模的问题一直出现在SO中。

如果您在诸如Java之类的OOPL中建模gen-spec,您将使用子类继承工具来为您处理细节。您只需定义一个类来处理通用对象,然后定义一个子类集合,每个类型对应一种特定对象。每个子类都会扩展泛化类。它简单明了。

不幸的是,关系数据模型没有内置的子类继承,据我所知,SQL数据库系统不提供任何此类工具。但你不是运气不好。您可以设计表格以与OOP的类结构平行的方式对gen-spec进行建模。然后,在将新项添加到通用类时,必须安排实现自己的继承机制。详情如下。

类结构相当简单,一个表用于gen类,一个表用于每个spec子类。这是一个很好的例子,来自Martin Fowler的网站。 Class Table Inheritance。请注意,在此图中,Cricketer既是子类又是超类。您必须选择在哪些表中使用哪些属性。该图显示了每个表中的一个示例属性。

棘手的细节是如何为这些表定义主键。 gen类表以通常的方式获取主键(除非此表是另一种泛化的特化,如Cricketers)。大多数设计师给主键一个标准名称,如“Id”。他们使用自动编号功能填充Id字段。 spec类表获得一个主键,可以命名为“Id”,但不使用自动编号功能。相反,每个子类表的主键被约束为引用通用表的主键。这使得每个专用主键成为外键和主键。请注意,在Cricketers的情况下,Id字段将引用Players中的Id字段,但Bowlers中的Id字段将引用Cricketers中的Id字段。

现在,当您添加新项目时,您必须保持参照完整性,这是如何 首先在gen表中插入一个新行,为主键提供所有属性的数据。自动编号机制生成唯一的主键。接下来,在适当的spec表中插入一个新行,包括其所有属性的数据,包括主键。您使用的主键是刚刚生成的全新主键的副本。这种主键的传播可以称为“穷人的继承”。

现在,当您希望所有通用数据与来自一个子类的所有专用数据一起使用时,您所要做的就是通过公共键连接两个表。与所涉及的子类无关的所有数据都将退出连接。它光滑,简单,快速。

实现gen-spec模式的SQL表的设计可能有点棘手。数据库设计教程经常掩盖这个主题。但它在实践中一次又一次地出现。

如果您在网上搜索“泛化专业化关系建模”,您会发现一些有用的文章,教您如何执行此操作。在本论坛之前,您还会多次指出这个主题。

文章通常向您展示如何设计单个表来捕获所有通用数据,以及如何为每个子类设计一个专用表,其中包含特定于该子类的所有数据。有趣的部分涉及子类表的主键。您不会使用DBMS的自动编号功能来填充子类主键。相反,您将对应用程序进行编程,以将为通用表获取的主键值传播到适当的子类表。

这在广义数据和专用数据之间创建了双向关联。每个专用子类的简单视图将一起收集通用和专用数据。一旦掌握了它就很容易,并且表现相当不错。

答案 1 :(得分:0)

通过强制将两个Java字段(id和association)映射到同一列来进行测试。

例如,

class Orange {

   @Id
   @Column(name="id")
   long id;


   @OneToOne
   @JoinColumn(name="id")
   Fruit fruit;

   public Orange(Fruit fruit) {
      this.fruit = fruit;
      this.id = fruit.id;
   }

   protected Orange() { } // default constructor required by JPA
}

但我不知道JPA提供商的行为方式。

相关问题