[英]Hibernate inheritance - OneToMany with 2 class that extend parent not work
[英]Why @OneToMany does not work with inheritance in Hibernate
@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 人被 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 人被 UglyProblem 类继承。
我希望这是因为所有其他映射字段都是继承的,我认为没有任何理由为多对一关系设置例外。
是的,我看到了。 事实上,我在我的案例中使用了只读解决方案。 但我的问题是“为什么...”:)。 我知道 hibernate 团队的一个成员给出了解释。 我找不到它,这就是我问的原因。
我想找出这个设计决策的动机。
(如果你对我如何面对这个问题感兴趣:我继承了一个使用 hibernate 3 构建的项目。它是 Jboss 4.0.something + hibernate 已经存在(你可以一起下载它)。我正在将这个项目转移到 Jboss 4.2。 2,我发现有“@OneToManymappedBy”的继承映射,它在旧设置上运行良好......)
在我的例子中,我想使用 SINGLE_TABLE 继承类型,所以使用 @MappedSuperclass 不是一个选项。
虽然不是很干净,但有效的是将 Hibernate 专有的@Where子句添加到 @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 进行编码,则可以更轻松地稍后更改底层映射(破坏兼容性的风险较小)。
我认为这是 Hibernate 团队做出的明智决定。 他们可以不那么傲慢,并明确说明为什么以这种方式实施,但这就是 Emmanuel、Chris 和 Gavin 的工作方式。 :)
让我们试着理解这个问题。 我认为你的概念是“撒谎”。 首先,您说许多Problem都与People相关联。 但是,然后你说一个Person有很多UglyProblem s(并且与其他Problem s 无关)。 那个设计有问题。
想象一下它将如何映射到数据库。 您只有一个表继承,因此:
_____________
|__PROBLEMS__| |__PEOPLE__|
|id <PK> | | |
|person <FK> | -------->| |
|problemType | |_________ |
--------------
如果问题类型等于 UP,hibernate 将如何强制数据库使问题仅与人员相关? 这是一个非常难以解决的问题。 所以,如果你想要这种关系,每个子类都必须在它自己的表中。 这就是@MappedSuperclass
所做的。
PS。:对不起,丑陋的图画:D
我认为您需要使用@MappedSuperclass而不是@Entity来注释您的问题超类。
我想出了如何解决 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 尊重鉴别器
需要休眠注释。
在我看来,@JoinColumn 至少应该提供一个选项来将 @DiscriminatorColumn = @DiscriminatorValue 应用于 SQL“where”子句,尽管我更希望这种行为是默认行为。
我很惊讶,在 2020 年,这仍然是一个问题。 由于这种对象设计模式并不罕见,我认为 JPA 还没有在规范中涵盖这个简单的特性是一种耻辱,因此仍然迫使我们寻找丑陋的解决方法。
为什么这必须如此困难? 这只是一个额外的 where 子句,是的,我确实为 @JoinColumn、@DiscriminatorColumn 组合准备了一个 db 索引。
.i..JPA
引入您自己的自定义注释并编写生成本机查询的代码。 这将是一个很好的锻炼。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.