0

Consider the below example:

I have 3 tables: Fruit, Orange and Apple

id is generated in fruit table and is the primary key here

id is also primary key for Orange and Apple (shared primary key)

So for e.g. if id in fruit is 1, 2, 3, 4, 5 -- then scenario could be 1, 2 are Orange, 3, 4 are Apple and 5 is again Orange..

So Orange table will have id 1,2,5 while Apple table will have 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
===================================

Issue: How to create entity classes capturing relationshipd also with only JPA annotations (I don't want to use hibernate generatedValue annotation).

If such annotation is possible with pure JPA then please guide me towards it.

Nik

4

2 回答 2

2

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

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

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

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

棘手的细节是如何为这些表定义主键。gen 类表以通常的方式获取主键(除非该表是另一种泛化的特化,例如 Cricketers)。大多数设计师给主键起一个标准的名字,比如“Id”。他们使用自动编号功能来填充 Id 字段。规格类表有一个主键,可以命名为“Id”,但不使用自动编号功能。相反,每个子类表的主键都被限制为引用通用表的主键。这使得每个专用主键既是外键又是主键。请注意,对于 Cricketers,Id 字段将引用 Players 中的 Id 字段,但 Bowlers 中的 Id 字段将引用 Cricketers 中的 Id 字段。

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

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

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

如果你在网上搜索“泛化专业化关系建模”,你会发现几篇有用的文章教你如何做到这一点。您还将在此论坛中多次指出该主题。

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

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

于 2012-07-31T10:07:24.817 回答
0

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

例如,

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 提供者会如何表现。

于 2011-10-05T12:10:04.330 回答