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



考虑下面的例子:

我有3张桌子:水果,橘子和苹果

id是在fruit table中生成的,是这里的主键

id也是橙子和苹果的主键(共享主键)

例如,如果水果中的id是1,2,3,4,5,那么场景可能是1,2是橙子,3,4是苹果,5也是橙子。

橙色表的id为1,2,5而苹果表的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中是可能的,那么请指导我。

尼克

您的案例看起来像是称为"泛化专门化"或简称为Gen-Spec的设计模式的实例。如何使用数据库表对gen-spec进行建模的问题在SO中一直出现。

如果您在像Java这样的OOPL中建模根规范,您将使用子类继承工具来为您处理细节。您只需定义一个类来处理泛化对象,然后定义一个子类集合,每种类型的专门化对象对应一个子类。每个子类都将扩展一般化类。这很简单,很直接。

不幸的是,关系数据模型没有内置子类继承,而且据我所知,SQL数据库系统不提供任何这样的功能。但你也不是没运气。您可以设计表以类似于OOP的类结构的方式对gen-spec进行建模。然后,在向一般化类添加新项时,必须安排实现自己的继承机制。细节。

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

棘手的细节是如何为这些表定义主键。gen类表以通常的方式获得一个主键(除非这个表是另一个泛化的专门化,比如Cricketers)。大多数设计师给主键一个标准的名字,比如"Id"。它们使用自动编号特性填充Id字段。spec类表有一个主键,可以命名为"Id",但没有使用自动编号特性。相反,每个子类表的主键被约束为引用一般化表的主键。这使得每个专门化主键既是主键又是外键。注意,在Cricketers的情况下,Id字段将引用Players中的Id字段,但是Bowlers中的Id字段将引用Cricketers中的Id字段。

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

现在,当您希望将所有通用数据与来自一个子类的所有专用数据结合在一起时,您所要做的就是通过公共键连接两个表。所有不属于所讨论的子类的数据都将从连接中删除。它光滑、简单、快速。

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

如果你在网上搜索"泛化专门化关系建模",你会发现一些教你如何做到这一点的有用文章。在这个论坛里,你也会被多次提到这个话题。

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

这在一般化数据和专门化数据之间创建了双向关联。每个专门化子类的简单视图将一起收集一般化和专门化数据。一旦你掌握了窍门,这很容易,而且它的性能相当好。

通过强制两个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提供者将如何行为

相关内容

  • 没有找到相关文章

最新更新