JPA - 多个表之间具有共享主键的一对一关系
考虑下面的例子:
我有3个表:Fruit、Orange和Apple
id是在fruit表中生成的,并且是这里的主键,
id也是Orange和Apple的主键(共享主键)
因此,例如,如果fruit中的id为1 , 2, 3, 4, 5 - 那么场景可能是 1, 2 是 Orange,3, 4 是 Apple,5 又是 Orange。
所以 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 可以使用此类注释,那么请指导我它。
尼克
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的案例看起来像是被称为“泛化专业化”(简称 Gen-Spec)的设计模式的一个实例。如何使用数据库表对 gen-spec 进行建模的问题在 SO 中一直出现。
如果您在 OOPL(例如 Java)中对 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 的自动编号功能来填充子类主键。相反,您将对应用程序进行编程,以便将从通用表获得的主键值传播到相应的子类表。
这在通用数据和专用数据之间创建了双向关联。每个专用子类的简单视图将一起收集通用和专用数据。一旦掌握了它的窍门,这很容易,而且性能相当好。
Your case looks like an instance of the design pattern known as “Generalization Specialization” , or Gen-Spec for short. The question of how to model gen-spec using database tables comes up all the time in SO.
If you were modeling gen-spec in an OOPL such as Java, you would use the subclass inheritance facility to take care of the details for you. You would simply define a class to take care of the generalized objects, and then define a collection of subclasses, one for each type of specialized object. Each subclass would extend the generalized class. It’s easy and straightforward.
Unfortunately the relational data model does not have subclass inheritance built in, and the SQL database systems don’t offer any such facility, to my knowledge. But you’re not out of luck. You can design your tables to model gen-spec in a way that parallels the class structure of OOP. You then have to arrange to implement your own inheritance mechanism when new items are added to the generalized class. Details follow.
The class structure is fairly simple, with one table for the gen class and one table for each spec subclass. Here’s a nice illustration, from Martin Fowler’s website. Class Table Inheritance. Note that in this diagram, Cricketer is both a subclass and a superclass. You have to choose which attributes go in which tables. The diagram shows one sample attribute in each table.
The tricky detail is how you define primary keys for these tables. The gen class table gets a primary key in the usual way (unless this table is a specialization of yet another generalization, like Cricketers). Most designers give the primary key a standard name, like “Id”. They use the autonumber feature to populate the Id field. The spec class tables get a primary key, which can be named “Id”, but the autonumber feature is not used. Instead the primary key of each subclass table is constrained to refer to the primary key of the generalized table. This makes each of the specialized primary keys a foreign key as well as a primary key. Note that in the case of Cricketers, the Id field will reference the Id field in Players, but the Id field in Bowlers will reference the Id field in Cricketers.
Now, when you add new items, you have to maintain referential integrity, Here’s how.
You first insert a new row into the gen table, providing data for all of its attributes, except the primary key. The autonumber mechanism generates a unique primary key. Next you insert a new row into the appropriate spec table, including data for all of its attributes, including the primary key. The primary key you use is a copy of the brand new primary key just generated. This propagation of the primary key can be called “poor man’s inheritance”.
Now when you want all the generalized data together with all the specialized data from just one subclass, all you have to do is join the two tables over the common keys. All the data that does not pertain to the subclass in question will drop out of the join. It’s slick, easy, and fast.
The design of SQL tables that implement the gen-spec pattern can be a little tricky. Database design tutorials often gloss over this topic. But it comes up again and again in practice.
If you search the web on “generalization specialization relational modeling” you’ll find several useful articles that teach you how to do this. You’ll also be pointed to several times this topic has come up before in this forum.
The articles generally show you how to design a single table to capture all the generalized data and one specialized table for each subclass that will contain all the data specific to that subclass. The interesting part involves the primary key for the subclass tables. You won’t use the autonumber feature of the DBMS to populate the sub class primary key. Instead, you’ll program the application to propagate the primary key value obtained for the generalized table to the appropriate subclass table.
This creates a two way association between the generalized data and the specialized data. A simple view for each specialized subclass will collect generalized and specialized data together. It’s easy once you get the hang of it, and it performs fairly well.
通过强制两个 Java 字段(id 和关联)映射到同一列来进行测试。
例如,
但我不知道 JPA 提供程序将如何表现。
To be tested by forcing the two Java fields (id and association) to map on the same column.
For instance,
But I don't know how the JPA provider will behave.