Java 为什么@OneToMany 不适用于 Hibernate 中的继承

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38057/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:29:43  来源:igfitidea点击:

Why @OneToMany does not work with inheritance in Hibernate

javahibernateinheritanceorm

提问by Georgy Bolyuba

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

I think it is pretty clear what I am trying to do. I expect @ManyToOne person to be inherited by UglyProblem class. But there will be an exception saying something like: "There is no such property found in UglyProblem class (mappedBy="person")".

我想我想要做什么已经很清楚了。我希望@ManyToOne 人被 UglyProblem 类继承。但是会有一个例外,比如:“在 UglyProblem 类中找不到这样的属性 (mappedBy="person")”。

All I found is this. I was not able to find the post by Emmanuel Bernard explaining reasons behind this.

我发现的只是这个。我找不到 Emmanuel Bernard 解释这背后的原因的帖子。



Unfortunately, according to the Hibernate documentation "Properties from superclasses not mapped as @MappedSuperclass are ignored."

不幸的是,根据 Hibernate 文档“未映射为 @MappedSuperclass 的超类的属性将被忽略。”

Well I think this means that if I have these two classes:

好吧,我认为这意味着如果我有这两个类:

public class A {
    private int foo;
}

@Entity
public class B extens A {
}

then field foowill not be mapped for class B. Which makes sense. But if I have something like this:

那么字段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;
}
}

I expect the class UglyProblem to have fileds idand nameand both classes to be mapped using same table. (In fact, this is exactly what happens, I have just checked again). I have got this table:

我希望 UglyProblem 类具有文件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;

Going back to my question:

回到我的问题:

I expect @ManyToOne person to be inherited by UglyProblem class.

我希望@ManyToOne 人被 UglyProblem 类继承。

I expect that because all other mapped fields are inherited and I do not see any reason to make this exception for ManyToOne relationships.

我希望这是因为所有其他映射字段都是继承的,我看不出有任何理由为多对一关系设置例外。



Yeah, I saw that. In fact, I used Read-Only solution for my case. But my question was "Why..." :). I know that there is an explanation given by a member of hibernate team. I was not able to find it and that is why I asked.

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

I want to find out the motivation of this design decision.

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

(if you interested how I have faced this problem: I inherited a project built using hibernate 3. It was Jboss 4.0.something + hibernate was already there (you'd download it all together). I was moving this project to Jboss 4.2.2 and I found out that there are inherited mappings of "@OneToMany mappedBy" and it worked fine on old setup...)

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

采纳答案by Marcio Aguiar

I think it's a wise decision made by the Hibernate team. They could be less arrogante and make it clear why it was implemented this way, but that's just how Emmanuel, Chris and Gavin works. :)

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

Let's try to understand the problem. I think your concepts are "lying". First you say that many Problems are associated to People. But, then you say that one Personhave many UglyProblems (and does not relate to other Problems). Something is wrong with that design.

让我们试着理解这个问题。我认为你的概念是“撒谎”。首先,您说许多Problem都与People相关联。但是,然后你说一个Person有很多UglyProblems(并且与其他Problems无关)。那个设计有问题。

Imagine how it's going to be mapped to the database. You have a single table inheritance, so:

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

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

How is hibernate going to enforce the database to make Problemonly relate to Peopleif its problemTypeis equal UP? That's a very difficult problem to solve. So, if you want this kind of relation, every subclass must be in it's own table. That's what @MappedSuperclassdoes.

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

PS.: Sorry for the ugly drawing :D

PS。:对不起,丑陋的图画:D

回答by Peter Hilton

I think you need to annotate your Problemsuper-class with @MappedSuperclassinstead of @Entity.

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

回答by David Crow

Unfortunately, according to the Hibernate documentation"Properties from superclasses not mapped as @MappedSuperclass are ignored." I ran up against this too. My solution was to represent the desired inheritance through interfaces rather than the entity beans themselves.

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

In your case, you could define the following:

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

public interface Problem {
    public Person getPerson();
}

public interface UglyProblem extends Problem {
}

Then implement these interfaces using an abstract superclass and two entity subclasses:

然后使用抽象超类和两个实体子类实现这些接口:

@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 {
}

As an added benefit, if you code using the interfaces rather than the actual entity beans that implement those interfaces, it makes it easier to change the underlying mappings later on (less risk of breaking compatibility).

作为一个额外的好处,如果您使用接口而不是实现这些接口的实际实体 bean 进行编码,则可以更轻松地稍后更改基础映射(破坏兼容性的风险较小)。

回答by Bill Leeper

I figured out how to do the OneToMany mappedBy problem.

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

In the derived class UglyProblem from the original post. The callback method needs to be in the derived class not the parent class.

在原帖的派生类 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;
}

Found the secret sauce for using Hibernate at least. http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/ForceDiscriminator.htmlThe @ForceDiscriminator makes the @OneToMany honor the discriminator

至少找到了使用 Hibernate 的秘诀。 http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/ForceDiscriminator.html@ForceDiscriminator 使 @OneToMany 尊重鉴别器

Requires Hibernate Annotations.

需要休眠注释。

回答by Guillaume Carre

In my case I wanted to use the SINGLE_TABLE inheritance type, so using @MappedSuperclass wasn't an option.

在我的例子中,我想使用 SINGLE_TABLE 继承类型,所以使用 @MappedSuperclass 不是一个选项。

What works, although not very clean, is to add the Hibernate proprietary @Whereclause to the @OneToMany association to force the type in queries:

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

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