java 休眠多态
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/979200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Hibernate polymorphism
提问by ae6rt
This is a Hibnerate polymorphism question and a data model design question; they are intertwingled. I've used Hibernate in the past, and have enjoyed it, but sometimes I find it difficult to think about anything but trivial designs. Not a knock on Hibernate; just an observation that ORM in general can be challenging.
这是一道Hibnate多态题和一道数据模型设计题;它们交织在一起。我过去使用过 Hibernate,并且很享受它,但有时我发现除了琐碎的设计之外很难考虑任何其他事情。不是对 Hibernate 的敲击;只是观察到 ORM 通常具有挑战性。
I think this is a Hibernate 101 question, but I am not sure. What I am trying to achieve may not even be possible.
我认为这是一个 Hibernate 101 问题,但我不确定。我试图实现的目标甚至可能是不可能的。
I have an abstract class Fruit that will be subclassed into Apple and Orange. I have a Note class that represents notes or comments about Apples and Oranges. An Apple or Orange can have many Notes associated with it, but only one Apple or Orange will ever be associated with a given Note.
我有一个抽象类 Fruit,它将被子类化为 Apple 和 Orange。我有一个 Note 类,代表关于苹果和橙子的笔记或评论。一个 Apple 或 Orange 可以关联多个 Notes,但只有一个 Apple 或 Orange 与给定的 Note 关联。
Here are sketches of the classes, where I am for now omitting where the object id's go, and the properties of Apples that distinguish them from Oranges. For the time being, I don't feel strongly about which Hibernate inheritance strategy I use.
下面是这些类的草图,我现在省略了对象 id 的位置,以及 Apples 将它们与 Oranges 区分开来的属性。目前,我对我使用的 Hibernate 继承策略没有强烈的感觉。
abstract public class Fruit {
}
// Apples have notes written about them:
public class Apple extends Fruit {
private Set<Note> note;
...
@OneToMany(cascade = CascadeType.ALL)
public Set<Note> getNote() {
return note;
}
}
// Oranges have notes written about them:
public class Orange extends Fruit {
private Set<Note> note;
...
@OneToMany(cascade = CascadeType.ALL)
public Set<Note> getNote() {
return note;
}
}
Here is the Note class currently implemented, wherein we see that it has fields for both an Apple and an Orange. The flaw or inelegance in this design is that a single note instance will only point to one of Apple or Orange, and never both. So if a Note is bound to an Apple, the Orange field is superfluous and unsightly, and viceversa.
这是当前实现的 Note 类,其中我们看到它具有 Apple 和 Orange 的字段。这种设计的缺陷或不雅之处在于单个音符实例只会指向 Apple 或 Orange 之一,而不会同时指向两者。所以如果一个 Note 绑定了一个 Apple,那么 Orange 字段是多余的和不雅观的,反之亦然。
// A note about an Apple or Orange
public class Note {
private String theNote;
private Apple apple;
private Orange orange;
...
// with the usual many to one mapping
@ManyToOne
@JoinColumn(name = "apple_id")
public Apple getApple() {
return apple;
}
// with the usual many to one mapping
@ManyToOne
@JoinColumn(name = "orange_id")
public Orange getOrange() {
return orange;
}
...
}
However, this is the Note class that I thinkI want to base my design on, but I'm not sure how to think about this with respect to Hibernate annotation and table mapping:
然而,这是提示类,我想我要我的基础上设计的,但我不知道如何思考这对于Hibernate的注释和表映射:
// A note about a fruit:
public class Note {
private String theNote;
private Fruit fruit;
...
}
whereupon fruit will be either an Apple or Orange instance.
因此,fruit 将是 Apple 或 Orange 实例。
Can this latter Note class, with its reference to a Fruit, which will actually hold an Apple or Orange, even be reconciled with Hibernate ORM mapping? If yes, can someone please talk about how.
后一个 Note 类引用了一个 Fruit,它实际上将包含一个 Apple 或 Orange,甚至可以与 Hibernate ORM 映射相协调吗?如果是的话,有人可以谈谈如何。
回答by Henning
This is absolutely possible. You could associate the notes with the abstract Fruitclass instead of repeating them in each of the implementations:
这是绝对可能的。您可以将注释与抽象Fruit类相关联,而不是在每个实现中重复它们:
@Entity
@Inheritance
public abstract class Fruit {
private Set<Note> notes;
...
@OneToMany(cascade = CascadeType.ALL, mappedBy = "fruit")
public Set<Note> getNotes() {
return notes;
}
}
@Entity
public class Apple extends Fruit {
...
}
@Entity
public class Orange extends Fruit {
...
}
@Entity
public class Note {
private String theNote;
@ManyToOne
private Fruit fruit;
...
}
ét voilà!
瞧!
-- Addition based on comment:JPA provides multiple strategies for dealing with inheritance. The relevant section in the Java EE tutorialshould help you get started.
-- 基于注释的补充:JPA 提供了多种处理继承的策略。Java EE 教程中的相关部分应该可以帮助您入门。
Basically, your options are:
基本上,您的选择是:
- Storing everything in one table and using a discriminator column to know which row is which type
- Storing each concrete class (Apple and Orange) in a separate table
- Having a common Fruit table with a discriminator column, and Apple and Orange tables with a foreign key to the Fruit table
- 将所有内容存储在一个表中并使用鉴别器列来知道哪一行是哪种类型
- 将每个具体类(Apple 和 Orange)存储在单独的表中
- 有一个带有鉴别器列的公共 Fruit 表,以及带有 Fruit 表外键的 Apple 和 Orange 表
Another edit:Noticed this is a Hibernate, not a JPA question. Does not make too much of a difference, though, as the options are the same. Here's the relevant section in the Hibernate docs.
另一个编辑:注意到这是一个 Hibernate,而不是一个 JPA 问题。不过,没有太大区别,因为选项是相同的。这是Hibernate 文档中的相关部分。
回答by Il-Bhima
This pattern is very common in Hibernate based datalayers. How it works internally is heavily based on which inheritance strategy is used.
这种模式在基于 Hibernate 的数据层中非常常见。它在内部如何工作在很大程度上取决于使用的继承策略。
When using table per class or table per subclass inheritance, a table for every subclass/class will be created. For example, in your case, you would have a table Fruit and two tables Appleand Orange, with foreign key references between Fruit and Apple/Orange. When requesting a single fruit (be it apple or orange) by ID, Hibernate will outer join the Fruit table with the Apple and Orange table. Each row will be transformed into an Apple or Orange depending on from which table the fields were retrieved.
当按类使用表或按子类继承使用表时,将为每个子类/类创建一个表。例如,在您的情况下,您将有一个表 Fruit 和两个表Appleand Orange,在 Fruit 和 Apple/Orange 之间有外键引用。当通过 ID 请求单个水果(苹果或橙子)时,Hibernate 会将 Fruit 表与 Apple 和 Orange 表外部连接。每一行都将转换为 Apple 或 Orange,具体取决于从哪个表中检索字段。
Another possibility is to use discriminators. A single table Fruitwill be used which will contain a discriminator field (ex. fruit_typetaking values appleand orange). Depending on the value of this field, Hibernate will determine whether the corresponding object is an Apple or an Orange.
另一种可能性是使用鉴别器。一个单一的表Fruit将被使用,这将包含一个鉴别字段(来自fruit_type拍摄值apple和orange)。根据该字段的值,Hibernate 将确定对应的对象是 Apple 还是 Orange。
In your case, in the case of eager loading, when Hibernate loads the Note object it will eagerly fetch the corresponding Fruit and populate the fruit field with an instance of Apple or Orange accordingly.
在您的情况下,在急切加载的情况下,当 Hibernate 加载 Note 对象时,它将急切地获取相应的 Fruit 并相应地用 Apple 或 Orange 的实例填充水果字段。
In the case of lazy fetching, the fruit field will be a proxy implementing the Fruit interface. Until the actual fruit field is loaded its type is undetermined.
在延迟获取的情况下,fruit 字段将是实现 Fruit 接口的代理。在加载实际的水果字段之前,它的类型是不确定的。
Hope this answers some of your queries.
希望这能回答您的一些疑问。

