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