为什么@OneToMany在Hibernate中不能inheritance

@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 problems; } 

我觉得很清楚我想做什么。 我希望@ManyToOne人能够被UglyProblem类inheritance。 但是会有例外情况说:“UglyProblem类中没有找到这样的属性(mappedBy =”person“)”。

我发现的就是这个 。 我无法找到Emmanuel Bernard解释其背后原因的post。


不幸的是,根据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具有fileds idname并且两个类都使用相同的表进行映射。 (事实上​​,这正是发生的事情,我刚刚再次检查过)。 我有这张桌子:

 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类inheritance。

我希望这是因为所有其他映射字段都是inheritance的,我没有看到任何理由为ManyToOne关系设置此exception。


是的,我看到了。 事实上,我在我的案例中使用了只读解决方案。 但我的问题是“为什么……”:)。 我知道hibernate团队成员有一个解释。 我无法找到它,这就是我问的原因。

我想找出这个设计决定的动机。

(如果你对我如何面对这个问题感兴趣:我inheritance了一个使用hibernate构建的项目3.它是Jboss 4.0.something + hibernate已经存在(你将它们全部下载)。我正在将这个项目移动到Jboss 4.2。 2,我发现有“@OneToMany mappedBy”的inheritance映射,它在旧的设置上运行良好…)

我认为这是Hibernate团队做出的明智决定。 他们可能不那么傲慢,并明确说明为什么以这种方式实施,但这就是Emmanuel,Chris和Gavin的工作方式。 🙂

让我们试着理解这个问题。 我认为你的概念是“撒谎”。 你说有很多问题与人有关。 但是,那么你说一个有许多UglyProblem (并且与其他问题无关)。 这个设计出了点问题。

想象一下它将如何映射到数据库。 您有一个表inheritance,所以:

  _____________ |__PROBLEMS__| |__PEOPLE__| |id  | | | |person  | -------->| | |problemType | |_________ | -------------- 

hibernate如何强制执行数据库以使问题仅与People相关,如果其problemType等于UP? 这是一个非常难以解决的问题。 所以,如果你想要这种关系,每个子类必须在它自己的表中。 这就是@MappedSuperclass的作用。

PS:很抱歉丑陋的画:D

在我的情况下,我想使用SINGLE_TABLEinheritance类型,因此使用@MappedSuperclass不是一个选项。

什么有用 ,虽然不是很干净,但是将Hibernate专有的@Where子句添加到@OneToMany关联以强制查询中的类型:

 @OneToMany(mappedBy="person") @Where(clause="DTYPE='UP'") private List< UglyProblem > problems; 

不幸的是,根据Hibernate 文档 “忽略了未映射为@MappedSuperclass的超类属性”。 我也遇到了这种情况。 我的解决方案是通过接口而不是实体bean本身来表示所需的inheritance。

在您的情况下,您可以定义以下内容:

 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而不是@Entity来注释您的Problem超类。

我想出了如何做OneToMany mappedBy问题。

在派生类UglyProblem中从原始post。 回调方法需要在派生类中而不是父类中。

 @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注释。