【问题标题】:Hibernate - ManyToMany using unique property of one of the mapped tablesHibernate - ManyToMany 使用映射表之一的唯一属性
【发布时间】:2016-06-04 04:22:16
【问题描述】:

Hibernate 不允许我使用唯一字段“docket”进行连接表,无论我是否指定“referencedColumnName = “docket””(我认为这个属性的想法是告诉 Hibernate 使用哪个字段,以防它不是主键)。

数据库表:

    student
---------------
  id (PK) | docket (UNIQUE)

  inscription
---------------
course_id | docket

inscription's PK is (course_id, docket)

    course
---------------
     id (PK)

使用以下配置会引发上述问题:

关于学生实体:

@ManyToMany
@JoinTable(
            name="inscription",
            joinColumns=@JoinColumn(referencedColumnName = "docket", name="docket"),
            inverseJoinColumns=@JoinColumn(name="course_id", referencedColumnName = "id")
)
private List<Course> studentCourses;

关于课程实体:

@ManyToMany(mappedBy = "studentCourses")
private List<Student> students;

导致问题的原因是,在部署项目时,Hibernate 执行语句:

alter table public.inscription add constraint FKp625s5r1hmlggpgeq4x2nju91 foreign key (docket) references public.student

这(当然)是不正确的,因为它没有指定 docket 是一个唯一的字段。

它应该做的是:

alter table public.inscription add constraint FKp625s5r1hmlggpgeq4x2nju91 foreign key (docket) references public.student(docket)

但我不知道如何告诉它这样做。

有什么帮助吗? 提前致谢。

【问题讨论】:

  • referencedColumnName 通常适用于关系末尾有多个 PK 字段的情况,因此您可以将不同的 PK 列与等效列对齐(s) 在连接表中。我知道 JPA 规范中没有任何内容允许使用非 PK 字段进行加入;确定 JPA 提供者可以允许,但您的似乎不允许。
  • 感谢您的评论!但是,据我所知,每个数据库表只能定义 PK,而表的其他 ID 需要定义为 UNIQUE。 PK 和 UNIQUE 都被数据库实现用作索引,但区别在于数据在数据库中的组织方式(它对 db 用户是透明的)。这就是为什么我认为使用 PK,JPA 文档指的是任何表的 ID(PK + UNIQUE 约束)。也许是指复合PK的一列,我误解了文档。

标签: java sql hibernate postgresql jpa


【解决方案1】:

在官方文档中找到了答案。

来自 JPA 2.0 文档:http://download.oracle.com/otndocs/jcp/persistence-2.0-fr-oth-JSpec/

11.1.21 加入列注解

JoinColumn 注解用于指定用于连接实体关联或元素的列 收藏。

...

name 注释元素定义外键列的名称。剩下的注释 元素(referencedColumnName 除外)引用此列并具有与 用于列注释。

如果缺少 referencedColumnName 元素,则假定外键引用主元素 被引用表的键。

支持不是被引用表的主键列的被引用列是可选的。 使用此类映射的应用程序将不可移植。

所以,也许是 Hibernate 没有实现这个功能,因为它不是强制性的。

我所做的修复它是修改题字表,用相应的主键替换每个字段。

【讨论】:

    【解决方案2】:

    (我认为这个属性的想法是告诉 Hibernate 使用哪个字段,以防它不是主键)

    您的假设与JPA 2.0 specification 相矛盾,前提是您使用 Hibernate 作为 JPA 的实现,因为以下摘录指出您必须加入主键。它没有说任何关于唯一字段的内容:

    2.10.4 双向多对多关系

    假设:

    • 实体 A 引用实体 B 的集合。

    • 实体 B 引用实体 A 的集合。

    • 实体 A 是关系的所有者。

    以下映射默认值适用:

    • 实体 A 映射到名为 A 的表。
    • 实体 B 映射到名为 B 的表。

    有一个名为 A_B(所有者名称在前)的连接表。此连接表有两个外键列。一个外键列引用表 A 并且与表 A 的主键具有相同的类型。该外键列的名称由以下连接形成: 实体 B 的关系属性或字段的名称; "_"; 表 A 中的主键列的名称

    另一个外键列引用表B,与表B的主键类型相同。该外键列的名称由以下连接形成:关系属性或字段的名称实体A; "_"; 表 B 中的主键列的名称

    (我添加了格式;文本是规范的原始引用。)

    docket 在您的情况下不是主键,因此您不能加入它。

    【讨论】:

    • 感谢您的回答!您能否添加引用答案的链接?提前致谢!
    • 我想给出源链接,但觉得很容易找到。 Herr 无论如何。
    • 谢谢!正如您所说,文档说“适用以下映射默认值:..”。但是,JPA 提供了不同的工具来避免使用这些默认配置,而这正是我所寻找的。我很确定它们应该存在,因为我想做的可以直接在数据库上编写命令。如果您能找到这些工具(注释的属性),请告诉我。再次感谢您花时间在这上面!我真的很感激。
    • 这里的术语defaults是关于持久提供者生成的表和列的名称,如果用户没有定义自己的。但是外键是指主键。您也可以在Hibernate documentation 阅读此内容。
    猜你喜欢
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    • 1970-01-01
    • 2011-06-22
    相关资源
    最近更新 更多