为什么 @OneToMany 不适用于 Hibernate 中的继承
-
09-06-2019 - |
题
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Problem {
@ManyToOne
private Person person;
}
@Entity
@DiscriminatorValue("UP")
public class UglyProblem extends Problem {}
@Entity
public class Person {
@OneToMany(mappedBy="person")
private List< UglyProblem > problems;
}
我想我想做什么已经很清楚了。我希望 @ManyToOne person 被 UglyProblem 类继承。但会有一个例外,比如:“在 UglyProblem 类中没有找到这样的属性(mappedBy =“person”)”。
我发现的只是 这. 。我找不到 Emmanuel Bernard 的帖子解释其背后的原因。
不幸的是,根据 Hibernate 文档,“未映射为 @MappedSuperclass 的超类的属性将被忽略”。
好吧,我认为这意味着如果我有这两门课:
public class A {
private int foo;
}
@Entity
public class B extens A {
}
然后场 foo
不会映射为 B 类。这是有道理的。但如果我有这样的东西:
@Entity
public class Problem {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
public class UglyProblem extends Problem {
private int levelOfUgliness;
public int getLevelOfUgliness() {
return levelOfUgliness;
}
public void setLevelOfUgliness(int levelOfUgliness) {
this.levelOfUgliness = levelOfUgliness;
}
}
我希望 UglyProblem 类有归档 id
和 name
并且两个类都使用同一个表进行映射。(事实上,这正是发生的情况,我刚刚又检查了一遍)。我有这张表:
CREATE TABLE "problem" (
"DTYPE" varchar(31) NOT NULL,
"id" bigint(20) NOT NULL auto_increment,
"name" varchar(255) default NULL,
"levelOfUgliness" int(11) default NULL,
PRIMARY KEY ("id")
) AUTO_INCREMENT=2;
回到我的问题:
我希望 @ManyToOne person 被 UglyProblem 类继承。
我希望如此,因为所有其他映射字段都是继承的,并且我看不出有任何理由为 ManyToOne 关系制定此例外。
是的,我看到了。事实上,我对我的案例使用了只读解决方案。但我的问题是“为什么......”:)。我知道 hibernate 团队的一名成员给出了解释。我找不到它,这就是我问的原因。
我想找出这个设计决定的动机。
(如果您对我如何面对这个问题感兴趣:我继承了一个使用 hibernate 3 构建的项目。这是 Jboss 4.0.something + hibernate 已经在那里了(你可以一起下载它)。我正在将此项目移至 Jboss 4.2.2,我发现存在“@OneToManymappedBy”的继承映射,并且它在旧设置上运行良好...)
解决方案
我认为这是 Hibernate 团队做出的明智决定。他们可以不那么傲慢,并清楚地说明为什么要这样实施,但这正是伊曼纽尔、克里斯和加文的工作方式。:)
让我们尝试理解这个问题。我认为你的概念是“谎言”。首先你说这么多 问题s 关联到 人们. 。但是,然后你说那一个 人 有很多 丑陋的问题s(并且不与其他 问题s)。这个设计有问题。
想象一下它将如何映射到数据库。您有一个表继承,因此:
_____________
|__PROBLEMS__| |__PEOPLE__|
|id <PK> | | |
|person <FK> | -------->| |
|problemType | |_________ |
--------------
hibernate将如何强制数据库使 问题 仅与 人们 如果它是 问题类型 等于UP吗?这是一个非常难解决的问题。因此,如果您想要这种关系,每个子类都必须位于它自己的表中。就是这样 @MappedSuperclass
做。
附:抱歉画得丑了:D
其他提示
就我而言,我想使用 SINGLE_TABLE 继承类型,因此使用 @MappedSuperclass 不是一个选项。
虽然不是很干净,但有效的方法是添加 Hibernate 专有的 @在哪里 @OneToMany 关联子句以强制查询中的类型:
@OneToMany(mappedBy="person")
@Where(clause="DTYPE='UP'")
private List< UglyProblem > problems;
不幸的是,根据 Hibernate 文档 “由于@mappedsuperclass被忽略,超级阶级的属性未映射。”我也反对这个。我的解决方案是通过接口而不是实体 bean 本身来表示所需的继承。
对于您的情况,您可以定义以下内容:
public interface Problem {
public Person getPerson();
}
public interface UglyProblem extends Problem {
}
然后使用抽象超类和两个实体子类实现这些接口:
@MappedSuperclass
public abstract class AbstractProblemImpl implements Problem {
@ManyToOne
private Person person;
public Person getPerson() {
return person;
}
}
@Entity
public class ProblemImpl extends AbstractProblemImpl implements Problem {
}
@Entity
public class UglyProblemImpl extends AbstractProblemImpl implements UglyProblem {
}
作为一个额外的好处,如果您使用接口而不是实现这些接口的实际实体 bean 进行编码,则以后可以更轻松地更改底层映射(破坏兼容性的风险较小)。
我认为你需要注释你的 问题 超一流的 @MappedSuperclass 代替 @实体.
我想出了如何解决 OneToMany 映射问题。
在原始帖子的派生类 UglyProblem 中。回调方法需要位于派生类中,而不是父类中。
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@ForceDiscriminator
public class Problem {
}
@Entity
@DiscriminatorValue("UP")
public class UglyProblem extends Problem {
@ManyToOne
private Person person;
}
@Entity
public class Person {
@OneToMany(mappedBy="person")
private List< UglyProblem > problems;
}
至少找到了使用 Hibernate 的秘诀。 http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/ForceDiscriminator.html @ForceDiscriminator 使 @OneToMany 尊重鉴别器
需要 Hibernate 注解。