如果我有
@Inheritance(strategy = InheritanceType.JOINED)
Organization{
}
Account extends Organization{
private Organization organization
}
Client extends Organization{
private Organization organization
}
User {
private Organization organization
}
当我调用userDAO.get(1)并返回User的实例时,hibernate如何知道给我一个Account而不是Client的实例?
答案 0 :(得分:2)
Hibernate对每个子表执行OUTER JOIN
:
SELECT *,
case
when a.id is not null then 0
when c.id is not null then 1
when u.id is not null then 2
end as clazz
FROM Organization o
OUTER JOIN Account a
OUTER JOIN Client c
OUTER JOIN User u
通过查看实际返回的OUTER JOIN
来确定实际类型。显然,Account
只有一个表,Client
和User
持有一个具有相同id
的记录 - 这表示实际类型。这就是尴尬的case
/ when
所做的。
如果存在鉴别器列,则仍然需要OUTER JOIN
,但更容易确定实际类型,因为它明确存储在数据库中。没有case
/ when
魔术。
正如您所看到的,这种继承策略效率很低。当您明确要求给定的子类型时,它会好得多,因为Hibernate将仅使用一个表执行JOIN
。
答案 1 :(得分:1)
对于每个记录,hibernate可以在主表中存储一个附加(鉴别器)列,指示使用哪种类型。
答案 2 :(得分:0)
注意:仅适用于SINGLE_TABLE
策略,请参阅@Tomazs对JOINED
策略的回复。
Hibernate将显式子类存储为数据库中的某种形式的枚举,通常作为字符串值。您可以使用@DescriminatorColumn
注释设置此列的名称,然后在子类上使用@DiscriminatorValue
注释。当Hibernate在数据库中存储Account
时,任何特定于Client
的行仍然存储为Account
但设置为null
,并且DiscriminatorColumn
设置为"Account"
。然后,当组织被反序列化时,Hibernate会查看DiscriminatorColumn
,看到Organization
是Account
,并返回该类型的对象。
DescriminatorColumn
可以更改为使用其他类型的数据,例如。不是字符串,使用columnDefinition
参数。默认情况下,此列的名称为DTYPE
,而没有DiscriminatorValue
的类的值是该类的名称。