10
@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 としてマップされていないスーパークラスのプロパティは無視されます。」

これは、これら2つのクラスがある場合、次のことを意味すると思います。

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 クラスに継承されることを期待しています。

他のすべてのマップされたフィールドは継承されており、ManyToOne の関係に対してこの例外を作成する理由が見当たらないため、私はそれを期待しています。


ええ、私はそれを見ました。実際、私の場合は読み取り専用ソリューションを使用しました。しかし、私の質問は「なぜ...」でした:)。休止状態チームのメンバーによる説明があることを知っています。見つけられなかったので質問させていただきました。

このデザイン決定の動機を知りたいです。

(私がこの問題にどのように直面したかに興味がある場合:hibernate 3を使用して構築されたプロジェクトを継承しました。それはJboss 4.0.something + hibernateがすでにそこにありました(すべて一緒にダウンロードします)。私はこのプロジェクトをJboss 4.2に移動していました。 2 そして、「@OneToMany mappedBy」の継承されたマッピングがあり、古いセットアップで正常に機能することがわかりました...)

4

6 に答える 6

8

私の場合、 SINGLE_TABLE 継承タイプを使用したかったので、 @MappedSuperclass を使用することはできませんでした。

あまりクリーンではありませんが、Hibernate 独自の@Where句を @OneToMany アソシエーションに追加して、クエリで型を強制することで機能します。

@OneToMany(mappedBy="person")
@Where(clause="DTYPE='UP'")
private List< UglyProblem > problems;
于 2014-09-29T00:44:00.207 に答える
6

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. :)

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 Person have many UglyProblems (and does not relate to other Problems). Something is wrong with that design.

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 Problem only relate to People if its problemType is 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 @MappedSuperclass does.

PS.: Sorry for the ugly drawing :D

于 2008-09-10T05:06:10.240 に答える
5

残念ながら、Hibernate のドキュメントによると、 「 @MappedSuperclass としてマップされていないスーパークラスのプロパティは無視されます。」私もこれにぶつかりました。私の解決策は、エンティティ Bean 自体ではなく、インターフェイスを介して目的の継承を表すことでした。

あなたの場合、次のように定義できます。

public interface Problem {
    public Person getPerson();
}

public interface UglyProblem extends Problem {
}

次に、抽象スーパークラスと 2 つのエンティティ サブクラスを使用して、これらのインターフェイスを実装します。

@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 ではなく、インターフェースを使用してコーディングすると、後で基礎となるマッピングを簡単に変更できます (互換性を損なうリスクが少なくなります)。

于 2008-09-02T07:56:52.333 に答える
1

@Entityの代わりに@MappedSuperclassで問題のスーパークラスに注釈を付ける必要があると思います。

于 2008-09-01T16:09:47.947 に答える
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 が必要です。

于 2009-12-17T18:28:11.677 に答える
-2

私の意見では、@JoinColumn は、少なくとも @DiscriminatorColumn = @DiscriminatorValue を SQL の "where" 句に適用するオプションを提供する必要がありますが、この動作をデフォルトの動作にすることをお勧めします。

2020年になっても、これがまだ問題であることに非常に驚いています。このオブジェクト設計パターンはそれほど珍しいものではないため、JPA が仕様でこの単純な機能をまだカバーしていないことは恥ずべきことだと思います。

なぜこれが難しいのでしょうか?これは単なる追加の where 句であり、@JoinColumn、@DiscriminatorColumn コンボ用に db インデックスを用意しています。

.i. JPA

独自のカスタム アノテーションを導入し、ネイティブ クエリを生成するコードを記述します。いい運動になります。

于 2020-06-16T12:03:37.020 に答える