org.hibernate.AnnotationException:referencedColumnNames 引用未映射到单个属性

Posted

技术标签:

【中文标题】org.hibernate.AnnotationException:referencedColumnNames 引用未映射到单个属性【英文标题】:org.hibernate.AnnotationException: referencedColumnNames referencing not mapped to a single property 【发布时间】:2014-02-27 10:54:52 【问题描述】:

我在 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

这是我在主/父表中的一对一映射。

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

【问题讨论】:

【参考方案1】:

问题的原因是您尝试使用单个连接列,而被引用实体的标识由多个列定义。您只需定义所有需要的连接列就可以了:

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

OT:您不需要 OneToOne 注释上的 targetEntity 属性。这已经由目标实体的类型定义: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 具有这样的功能,例如通过查询进行一对一,但我无法确认。

EDIT2:连接表应包含两个实体的所有 PK 列才能完全发挥作用。这就是为什么我在示例中为每一侧定义了两个连接列。列数及其名称纯粹是示例性的。

仅提取表中已有的一个连接列不会增加任何价值。

最佳解决方案是更改实体表,以便它们定义实体之间的正确关系。只需更改其中一个表并将其定义为拥有方就足够了,就像您所做的那样,但使​​用所有 FK 列。这将需要迁移工作,因为您需要为缺少的 FK 列添加数据,如上所述。

EDIT3:我推荐的策略是基于您希望拥有完整的 CRUD 功能的假设。如果您只想提取数据以进行显示或报告,则视图非常好。您可以定义所需的列并将整个视图映射到单个实体。但是,由于它是一个视图,您将无法更改或迁移数据。

【讨论】:

谢谢科斯塔。看起来我的编辑没有保存/更新。我在***.com/questions/11206000/… 上看到了类似的回复。第二个表(子表)具有 2 列的复合主键。在 2 列中,一列的数据与第一个表的数据匹配。第二列完全不同。所以,我不确定如何加入超过 1 列。这就是为什么我在 one2one 连接上只添加了一列。 这些表是遗留系统的一部分。数据是平的。最好我想找到一种不添加/编辑第二个表的方法。提前致谢。 如果我理解正确,您的建议是创建一个新表,用于将两个表之间的一个公用键(列)存储到一个新表中。那正确吗?但是我没有得到语法。为什么有 2 个连接列,特别是 REFERRALS_ID2 和 REFFLG2 的第二个?感谢您的帮助。 我还将与我的 dba 核对是否可以选择向表 1 和 2 添加新主键并很好地定义外键关系;将检查是否可以将表 1 的复合键添加到表 2。 最好修改现有表,请查看编辑。【参考方案2】:

您可以在 @ManyToOne 上使用 targetEntity。 targetEntity 应该等于父(可能是抽象的)类。 临时解决方案取决于您的类层次结构: https://hibernate.atlassian.net/browse/HHH-4975

【讨论】:

以上是关于org.hibernate.AnnotationException:referencedColumnNames 引用未映射到单个属性的主要内容,如果未能解决你的问题,请参考以下文章