为什么@OneToMany在Hibernate中不能与继承一起使用

时间:2008-09-01 15:21:01

标签: java hibernate inheritance orm

@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“)”。

我找到的只是this。我无法找到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类具有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类继承。

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


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

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

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

6 个答案:

答案 0 :(得分:6)

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

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

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

答案 1 :(得分:5)

不幸的是,根据Hibernate documentation“来自超类的属性未被映射为@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进行编码,则可以更轻松地在以后更改基础映射(降低破坏兼容性的风险)。

答案 2 :(得分:4)

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

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

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

          _____________
          |__PROBLEMS__|          |__PEOPLE__|
          |id <PK>     |          |          |
          |person <FK> | -------->|          |
          |problemType |          |_________ |
          -------------- 

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

PS:很抱歉丑陋的画作:D

答案 3 :(得分:1)

我认为您需要使用 @MappedSuperclass 而不是 @Entity 来注释您的问题超类。

答案 4 :(得分:0)

我想出了如何解决OneToMany mappedBy问题。

在原始帖子的派生类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 Annotations。

答案 5 :(得分:-2)

我认为@JoinColumn至少应提供一个选项,将@DiscriminatorColumn = @DiscriminatorValue应用于SQL“ where”子句,尽管我希望此行为是默认行为。

对于2020年这仍然是一个问题,我感到非常惊讶。 由于这种对象设计模式并不罕见,因此我认为JPA尚未涵盖规范中的这一简单功能是一个可耻的事情,因此仍然迫使我们寻找丑陋的解决方法。

为什么要这么困难?这只是一个附加的where子句,是的,我确实为@JoinColumn和@DiscriminatorColumn组合准备了一个数据库索引。

.i .. JPA

介绍您自己的自定义注释,并编写生成本机查询的代码。这将是一个很好的锻炼。