web-dev-qa-db-ja.com

Hibernate @Any関連のアノテーションを使用する方法は?

Any関連の注釈(@Any@AnyMetaDef@AnyMetaDefs、および@ManyToAny)が実際にどのように機能するかを誰かに説明してもらえますか。これらに関する有用なドキュメントを見つけるのに苦労しています(JavaDocだけではあまり役に立ちません)。

私はこれまで、それらが何らかの形で抽象クラスと拡張クラスへの参照を可能にすることを収集しました。この場合、なぜ@OneToAnyアノテーションがないのですか?そして、これは「any」が単一の「any」を指しているのか、それとも複数の「any」を指しているのか?

短く、実用的で説明的な例をいただければ幸いです(コンパイルする必要はありません)。

編集:回答として返信を受け入れ、必要に応じてクレジットを付与したいのと同じくらい、SminkとSakanaの両方の回答が有益であることがわかりました。 回答として複数の返信を受け入れることができないため、残念ながらどちらも回答としてマークしません。

29
Henrik Paul

これを願っています 記事 主題にいくつかの光をもたらします:

場合によっては、関連付けプロパティを、共通の祖先エンティティを持たないさまざまなタイプのエンティティにマップする必要があります。そのため、単純な多態的な関連付けでは機能しません。

たとえば、メディアライブラリを管理する3つの異なるアプリケーションを想定します。最初のアプリケーションは本の借用を管理し、2番目のアプリケーションはDVDを管理し、3番目のアプリケーションはVHSを管理します。アプリケーションに共通点はありません。ここで、3つのメディアタイプすべてを管理し、既存のBook、DVD、およびVHSエンティティを再利用する新しいアプリケーションを開発したいと思います。 Book、DVD、およびVHSクラスは異なるアプリケーションからのものであるため、祖先エンティティはありません。共通の祖先はJava.lang.Objectです。それでも、可能なメディアタイプのいずれかを参照できる1つの借入エンティティが必要です。

このタイプの参照を解決するために、任意のマッピングを使用できます。このマッピングには常に複数の列が含まれます。1つの列には現在マップされているプロパティが参照するエンティティのタイプが含まれ、もう1つの列にはエンティティのIDが含まれます。たとえば、本を参照する場合、最初の列には次のマーカーが含まれます。 Bookエンティティタイプと2番目のエンティティタイプには、特定の本のIDが含まれます。

@Entity
@Table(name = "BORROW")
public class Borrow{

    @Id
    @GeneratedValue
    private Long id;

    @Any(metaColumn = @Column(name = "ITEM_TYPE"))
    @AnyMetaDef(idType = "long", metaType = "string", 
            metaValues = { 
             @MetaValue(targetEntity = Book.class, value = "B"),
             @MetaValue(targetEntity = VHS.class, value = "V"),
             @MetaValue(targetEntity = DVD.class, value = "D")
       })
    @JoinColumn(name="ITEM_ID")
    private Object item;

     .......
    public Object getItem() {
        return item;
    }

    public void setItem(Object item) {
        this.item = item;
    }

}
24
Jorge Ferreira

@Anyアノテーションは、複数のテーブルのクラスへの多態的な関連付けを定義します。このタイプのマッピングには、常に複数の列が必要です。最初の列は、関連付けられたエンティティのタイプを保持します。残りの列は識別子を保持します。この種の関連付けに外部キー制約を指定することは不可能であるため、これは(多態的な)関連付けをマッピングする通常の方法として意図されたものではありません。これは、非常に特殊な場合(監査ログ、ユーザーセッションデータなど)でのみ使用する必要があります。 @Anyアノテーションは、メタデータ情報を保持する列を記述します。メタデータ情報の値と実際のエンティティタイプをリンクするには、@ AnyDefアノテーションと@AnyDefsアノテーションを使用します。

@Any( metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
@AnyMetaDef(
    idType = "integer",
    metaType = "string",
    metaValues = {
        @MetaValue( value = "S", targetEntity = StringProperty.class ),
        @MetaValue( value = "I", targetEntity = IntegerProperty.class )
} )
@JoinColumn( name = "property_id" )
public Property getMainProperty() {
    return mainProperty;
}

idTypeはターゲットエンティティ識別子のプロパティタイプを表し、metaTypeはメタデータタイプ(通常は文字列)を表します。 @AnyDefは相互化して再利用できることに注意してください。この場合、パッケージメタデータとして配置することをお勧めします。

//on a package
@AnyMetaDef( name="property"
idType = "integer",
metaType = "string",
metaValues = {
@MetaValue( value = "S", targetEntity = StringProperty.class ),
@MetaValue( value = "I", targetEntity = IntegerProperty.class )
} )
package org.hibernate.test.annotations.any;
//in a class
@Any( metaDef="property", metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
@JoinColumn( name = "property_id" )
public Property getMainProperty() {
    return mainProperty;
}

@ManyToAnyを使用すると、複数のテーブルのクラスに多態的に関連付けることができます。このタイプのマッピングには、常に複数の列が必要です。最初の列は、関連付けられたエンティティのタイプを保持します。残りの列は識別子を保持します。この種の関連付けに外部キー制約を指定することは不可能であるため、これは(多態的な)関連付けをマッピングする通常の方法として意図されたものではありません。これは、非常に特殊な場合(監査ログ、ユーザーセッションデータなど)でのみ使用する必要があります。

@ManyToAny(
metaColumn = @Column( name = "property_type" ) )
@AnyMetaDef(
    idType = "integer",
    metaType = "string",
    metaValues = {
@MetaValue( value = "S", targetEntity = StringProperty.class ),
@MetaValue( value = "I", targetEntity = IntegerProperty.class ) } )
@Cascade( { org.hibernate.annotations.CascadeType.ALL } )
@JoinTable( name = "obj_properties", joinColumns = @JoinColumn( name = "obj_id" ),
    inverseJoinColumns = @JoinColumn( name = "property_id" ) )
public List<Property> getGeneralProperties() {

Src: Hibernate Annotationsリファレンスガイド3.4.0GA

それが役に立てば幸い!

23
sakana

@Anyアノテーションは、複数のテーブルのクラスへの多態的な関連付けを定義しますが、これらのような多態的な関連付けはSQLのアンチパターンです。主な理由は、列が複数のテーブルを参照できる場合、FK制約を定義できないことです。

Bill Karwinが著書で指摘している解決策の1つは、「type」で1つの列を使用する代わりに、「Any」のタイプごとに交差テーブルを作成し、重複を避けるために一意の修飾子を使用することです。このソリューションは、JPAを使用するのが面倒な場合があります。

Karwinによって提案された別の解決策は、接続された要素のスーパータイプを作成することです。 Book、DVD、またはVHSを借用する例をとると、結合テーブルの戦略を使用して、スーパータイプのアイテムを作成し、Book、DVD、およびVHSをアイテムから継承させることができます。次に、借用はアイテムをポイントします。このようにして、FKの問題を完全に回避します。この本の例を次のJPAに翻訳しました。

@Entity
@Table(name = "BORROW")
public class Borrow{
//... id, ...
@ManyToOne Item item;
//...
}

@Entity
@Table(name = "ITEMS")
@Inheritance(strategy=JOINED)
public class Item{
  // id, ....
  // you can add a reverse OneToMany here to borrow.
}

@Entity
@Table(name = "BOOKS")    
public class Book extends Item {
  // book attributes
}

@Entity
@Table(name = "VHS")    
public class VHS extends Item {
  // VHSattributes
}

@Entity
@Table(name = "DVD")    
public class DVD extends Item {
  // DVD attributes
}
2
atorres

@ AnyのHibernateアノテーションドキュメント を読んだことがありますか?私自身はまだそれを使用していませんが、参照を定義するための拡張された方法のように見えます。リンクには例が含まれていますが、概念を完全に理解するのに十分かどうかはわかりません...

2
Martin Klinke