複数の列を介して結合したい2つのエンティティがあります。これらの列は、@Embeddable
両方のエンティティによって共有されるオブジェクト。以下の例では、Foo
にはBar
を1つだけ含めることができますが、Bar
には複数のFoo
sを含めることができます(AnEmbeddableObject
はBar
)。以下に例を示します。
@Entity
@Table(name = "foo")
public class Foo {
@Id
@Column(name = "id")
@GeneratedValue(generator = "seqGen")
@SequenceGenerator(name = "seqGen", sequenceName = "FOO_ID_SEQ", allocationSize = 1)
private Long id;
@Embedded
private AnEmbeddableObject anEmbeddableObject;
@ManyToOne(targetEntity = Bar.class, fetch = FetchType.LAZY)
@JoinColumns( {
@JoinColumn(name = "column_1", referencedColumnName = "column_1"),
@JoinColumn(name = "column_2", referencedColumnName = "column_2"),
@JoinColumn(name = "column_3", referencedColumnName = "column_3"),
@JoinColumn(name = "column_4", referencedColumnName = "column_4")
})
private Bar bar;
// ... rest of class
}
そして、Barクラス:
@Entity
@Table(name = "bar")
public class Bar {
@Id
@Column(name = "id")
@GeneratedValue(generator = "seqGen")
@SequenceGenerator(name = "seqGen", sequenceName = "BAR_ID_SEQ", allocationSize = 1)
private Long id;
@Embedded
private AnEmbeddableObject anEmbeddableObject;
// ... rest of class
}
最後にAnEmbeddedObject
クラス:
@Embeddable
public class AnEmbeddedObject {
@Column(name = "column_1")
private Long column1;
@Column(name = "column_2")
private Long column2;
@Column(name = "column_3")
private Long column3;
@Column(name = "column_4")
private Long column4;
// ... rest of class
}
明らかにスキーマは不十分に正規化されており、各テーブルでAnEmbeddedObject
のフィールドが繰り返されるという制限があります。
私が抱えている問題は、Hibernateを起動しようとするとこのエラーが表示されることです。
org.hibernate.AnnotationException: referencedColumnNames(column_1, column_2, column_3, column_4) of Foo.bar referencing Bar not mapped to a single property
JoinColumnsが挿入および更新可能ではないが、運が悪いとマークしようとしました。 Hibernate/JPAアノテーションでこれを表現する方法はありますか?
これは私のために働いた。私の場合、2つのテーブルfooとbooは3つの異なる列に基づいて結合する必要があります。私の場合、3つの共通列は主キーではないことに注意してください
つまり、3つの異なる列に基づく1対1のマッピング
@Entity
@Table(name = "foo")
public class foo implements Serializable
{
@Column(name="foocol1")
private String foocol1;
//add getter setter
@Column(name="foocol2")
private String foocol2;
//add getter setter
@Column(name="foocol3")
private String foocol3;
//add getter setter
private Boo boo;
private int id;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "brsitem_id", updatable = false)
public int getId()
{
return this.id;
}
public void setId(int id)
{
this.id = id;
}
@OneToOne
@JoinColumns(
{
@JoinColumn(updatable=false,insertable=false, name="foocol1", referencedColumnName="boocol1"),
@JoinColumn(updatable=false,insertable=false, name="foocol2", referencedColumnName="boocol2"),
@JoinColumn(updatable=false,insertable=false, name="foocol3", referencedColumnName="boocol3")
}
)
public Boo getBoo()
{
return boo;
}
public void setBoo(Boo boo)
{
this.boo = boo;
}
}
@Entity
@Table(name = "boo")
public class Boo implements Serializable
{
private int id;
@Column(name="boocol1")
private String boocol1;
//add getter setter
@Column(name="boocol2")
private String boocol2;
//add getter setter
@Column(name="boocol3")
private String boocol3;
//add getter setter
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "item_id", updatable = false)
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
}
これがうまくいかない場合、私はアイデアがありません。この方法で、両方のテーブル(Bar
が所有し、Foo
がBar
を参照するため)と両方のエンティティで生成されたIDの4つの列を取得します。 4列のセットはBar
で一意である必要があるため、多対1のリレーションは多対多になりません。
@Embeddable
public class AnEmbeddedObject
{
@Column(name = "column_1")
private Long column1;
@Column(name = "column_2")
private Long column2;
@Column(name = "column_3")
private Long column3;
@Column(name = "column_4")
private Long column4;
}
@Entity
public class Foo
{
@Id
@Column(name = "id")
@GeneratedValue(generator = "seqGen")
@SequenceGenerator(name = "seqGen", sequenceName = "FOO_ID_SEQ", allocationSize = 1)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumns({
@JoinColumn(name = "column_1", referencedColumnName = "column_1"),
@JoinColumn(name = "column_2", referencedColumnName = "column_2"),
@JoinColumn(name = "column_3", referencedColumnName = "column_3"),
@JoinColumn(name = "column_4", referencedColumnName = "column_4")
})
private Bar bar;
}
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {
"column_1",
"column_2",
"column_3",
"column_4"
}))
public class Bar
{
@Id
@Column(name = "id")
@GeneratedValue(generator = "seqGen")
@SequenceGenerator(name = "seqGen", sequenceName = "BAR_ID_SEQ", allocationSize = 1)
private Long id;
@Embedded
private AnEmbeddedObject anEmbeddedObject;
}
Hibernateは、あなたがしようとしていることをあなたが簡単にできるようにするつもりはありません。 Hibernate documentation から:
ReferenceColumnNameを非プライマリキー列に使用する場合、関連付けられたクラスはSerializableである必要があることに注意してください。 また、非主キー列へのreferencedColumnNameは、単一の列を持つプロパティにマップする必要があることに注意してください(他の場合は機能しない可能性があります)。(強調を追加)
したがって、AnEmbeddableObject
をBarの識別子にしたくない場合、Hibernateは遅延なく、自動的にBarを取得します。もちろん、HQLを使用してAnEmbeddableObject
に参加するクエリを作成することもできますが、Barに複数列の非プライマリキーを使用すると主張すると、自動フェッチとライフサイクルのメンテナンスが失われます。