2

OneToOneリレーションシップを使用して、オプションのデータ ( ExtraData) をメイン クラス ( ) に追加しようとしていますMainItem。のすべてのインスタンスをExtraDataのインスタンスにリンクする必要がありMainItemますが、 のすべてのインスタンスがMainItemのインスタンスを持つ必要はありませんExtraData

(私は主に一方向の関係に興味がありますが、 to の更新と削除をカスケードできるようにするには、双方向の関係が必要なようMainItemですExtraData。)

と を双方向の関係と一緒に使用するのに問題が@Idあります。@OneToOne@JoinColumn

クラスは次のとおりです (単方向)。

@Entity
@Table(name = "main_item")
public class MainItem implements Serializable {
    @Id
    @Column(name = "id")
    private int id;

    @Column(name = "name")
    private String name;

    // + getters, setters, toString, ...
}

@Entity
@Table(name = "extra_data")
public class ExtraData implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @OneToOne
    @JoinColumn(name = "item_id")
    private MainItem item;

    @Column(name = "extra")
    private String extra;

    // + getters, setters, toString, ...
}

を使用してhbm2ddl.auto=updateいますが、次のデータも直接挿入しました。

INSERT INTO main_item(id, name) VALUES (1, 'Test A');
INSERT INTO main_item(id, name) VALUES (2, 'Test B');

INSERT INTO extra_data(item_id, extra) VALUES (1, 'Extra A');

この一方向の関係により、追加のデータとその主な項目の取得は正常に機能します。

Collection<ExtraData> extras = session.createCriteria(ExtraData.class)
        .list();
for (ExtraData extra : extras) {
    System.out.println(String.format("%s: %s", extra.getItem(), extra));
}

これは出力です:

Hibernate: select this_.item_id as item2_0_0_, this_.extra as extra1_0_0_ from extra_data this_
Hibernate: select mainitem0_.id as id1_1_0_, mainitem0_.name as name2_1_0_ from main_item mainitem0_ where mainitem0_.id=?
Test A: Extra A

他の関係を追加し@OneToOneて関係を双方向にすると、インスタンスを取得するときにまったく同じクエリでMainItemインスタンスが取得されなくなりExtraDataます。

MainItem(+get/set) に追加されたコードは次のとおりです。

@OneToOne(mappedBy = "item", cascade = CascadeType.ALL)
private ExtraData extraData;

さて、前のコードの出力は次のとおりです。

Hibernate: select this_.item_id as item2_0_0_, this_.extra as extra1_0_0_ from extra_data this_
null: Extra A

この逆の関係を追加すると、MainItemインスタンスを取得できなくなる理由がよくわかりません。それはすべて@Id@OneToOneと を@JoinColumn一緒に使用することに関係しているようですExtraDataこれは古いバージョンでは不可能だったことに気づきましたが、これをサポートするはずの Hibernate 4.2 を使用しています (ただし、有効にする特定の構成設定があるかどうかはわかりません)。

同じ列をメンバーに使用すると機能しますが、これが他の競合を引き起こさないかどうかはわかりません:

@Id
@Column(name = "item_id")
private int itemId;

@OneToOne
@JoinColumn(name = "item_id")
private MainItem item;

@Idメンバーとは別のものを使用せずにバリアントを取得することはできませんでした@OneToOneが、次のバリアントは機能しているようです (少なくともそのテスト クエリでは)。Hibernate 4.2 でこれを行う正しい方法は何ですか?

  • 使用@PrimaryKeyJoinColumn:

    @Id
    @Column(name = "item_id")
    private int itemId;
    
    @OneToOne
    @PrimaryKeyJoinColumn
    private MainItem item;
    
  • 使用@MapsId:

    @Id
    @Column(name = "item_id")
    private int itemId;
    
    @OneToOne
    @MapsId
    private MainItem item;
    

編集:

明確にするために、私は と の間の完全な双方向関係を望んでいるわけではありませんが、MainItem両方ExtraDataのデータセットを可能な限り分離しようとしています。

プレーン SQL では、次のようにします。

CREATE TABLE main_item (
    id INTEGER PRIMARY KEY,
    name TEXT
);
CREATE TABLE extra_data (
    item_id INTEGER PRIMARY KEY
        REFERENCES main_item(id) ON UPDATE CASCADE ON DELETE CASCADE,
    extra TEXT
);

ここで、 の関心事はmain_itemについて何も知る必要はありませんextra_data。関係するものはextra_dataすべて、おそらく後で、他の誰かによってコード化および処理される可能性があります。

はい、誰かが のmain_item別の行によって参照されている の行を削除するとextra_data、 の行extra_dataも削除されます。

Hibernate では、生成された外部キー制約でカスケードが宣言されていないため、また、反対側の観点からは宣言されているように見えるため、削除がカスケードされるように、少なくとも in に双方向の関係が必要なよう@OneToOne(mappedBy = "item", cascade = CascadeType.ALL) private ExtraData extraData;ですMainItem(そうしないと、外部キー制約がデータベースにあるため、インスタンスの削除MainDataは失敗します)。

理想的には、 に関連するコードとデータ モデルExtraDataが のコードに依存するようにしたいのですMainItemが、オリジナルはそれがもたらす新しいメンバーMainItemについて知る必要はありません。ExtraData

4

1 に答える 1

1

オプション@SecondaryTable @Tableはオプションですか?

@Entity
@Table(name="MAIN_DATA")
@SecondaryTable(name="EXTRA_DATA")
[@org.hibernate.annotations.Table(
   appliesTo="EXTRA_DATA",
   fetch=FetchMode.SELECT,
   optional=true)

MainItem に含めることができる

class MainItem {
  @Column(name="extra", table="EXTRA_DATA")
  private String extra;
  // ...and others field

  public void setExtraData(ExtraData extra) {
    this.extra = extra.getExtra();
    // etc...  
  }

  public ExtraData getExtraData() {
    ExtraData extraData = new ExtraData();

    extraData.setExtra(this.extra);
    // etc...  
  }
}

それが役立つことを願っています

于 2013-08-17T16:00:50.930 に答える