web-dev-qa-db-ja.com

org.hibernate.AnnotationException:単一のプロパティにマップされていない参照するreferencedColumnNames

2つのエンティティ間で1対1をマッピングしているときに、以下の例外が発生しました。最初の1つのエンティティには、複合キーが埋め込まれています。 2番目のエンティティにも複合キーが埋め込まれています。テーブルはレガシーシステムの一部です。データはフラットで、関係は明確に定義されていません。助けてください。

Caused by: org.hibernate.AnnotationException: referencedColumnNames(FLAG_NAME) of net.javabeat.spring.model.ReferralsM.mnEditFlag referencing net.javabeat.spring.model.MnEditFlag not mapped to a single property
    at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.Java:205)
    at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.Java:116)
    at org.hibernate.cfg.Configuration.processEndOfQueue(Configuration.Java:1515)
    at org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.Java:1440)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.Java:1358)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.Java:1727)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.Java:1778)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.Java:247)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.Java:373)
    at org.springframework.orm.hibernate4.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.Java:358)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.Java:1571)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.Java:1509)
    ... 34 more

これがメイン/親テーブルでの1対1のマッピングです。

@OneToOne(targetEntity = MnEditFlag.class, fetch = FetchType.LAZY)
@JoinColumn(name = "REFFLG", referencedColumnName = "FLAG_NAME", insertable = false,     updatable = false)
MnEditFlag mnEditFlag;
11
Superman9999

この問題の原因は、参照されているエンティティのIDが複数の列で定義されているのに、単一の結合列を使用しようとしていることです。必要なすべての参加列を定義するだけで、次のことができます。

@JoinColumns({
   @JoinColumn(name = "REFFLG", referencedColumnName = "FLAG_NAME"),
   @JoinColumn(name = "OTHER_KEY", referencedColumnName = "SOME_OTHER_NAME"))
   ...
})
MnEditFlag mnEditFlag;

OT:targetEntityアノテーションにOneToOne属性は必要ありません。これは、ターゲットエンティティのタイプMnEditFlagによってすでに定義されています。おそらく、型指定されていないtargetEntityに対してのみCollectionsが必要です。

編集:PKの一部にすぎない単一の結合列があり、既存のテーブルを変更できない場合は、必要なすべての列を使用して新しい結合テーブルを定義できます。

次に、関係に使用する結合テーブルを定義します。

@JoinTable(name="ReferralsM_MnEditFlag",
  joinColumns={
    @JoinColumn(name="REFERRALS_ID1", referencedColumnName="ID1"),
    @JoinColumn(name="REFERRALS_ID2", referencedColumnName="ID2")
  }, inverseJoinColumns={
    @JoinColumn(name="REFFLG", referencedColumnName="FLAG_NAME"),
    @JoinColumn(name="REFFLG2", referencedColumnName="FLAG_NAME2")
})  
MnEditFlag mnEditFlag;  

プログラムまたはクエリによって、データを新しい結合テーブルに移行する必要があります。

残念ながら、Vanilla JPAを使用して部分PKとの関係を定義することはできません。おそらく、Hibernateにはクエリによる1対1のような機能がありますが、確認できません。

EDIT2:完全に機能するには、結合テーブルに両方のエンティティのすべてのPK列が含まれている必要があります。そのため、この例では、両側に2つの結合列を定義しました。列の数とその名前は、純粋に例示的なものです。

テーブルにすでにある結合列を1つだけ抽出しても、値は追加されません。

最適な解決策は、エンティティテーブルを変更して、エンティティ間の適切な関係を定義することです。テーブルの1つだけを変更し、それを所有側として定義するだけで十分ですが、すべてのFK列を使用します。上記のように欠落しているFK列のデータを追加する必要があるため、これには移行作業が必要になります。

EDIT3:私が推奨した戦略は、完全なCRUD機能を持たせたいという主張に基づいていました。表示またはレポート用にデータをプルするだけの場合は、ビューはまったく問題ありません。必要な列を定義し、ビュー全体を単一のエンティティにマップできます。ただし、ビューであるため、データを変更したり、移行したりすることはできません。

17
kostja

@ManyToOneでtargetEntityを使用できます。 targetEntityは、親(おそらく抽象)クラスと同じである必要があります。一時的な解決策は、クラス階層に応じてここにあります: https://hibernate.atlassian.net/browse/HHH-4975

0
Youness