【问题标题】:composite unique constraint in OneToMany relationshipOneToMany 关系中的复合唯一约束
【发布时间】:2014-09-27 07:13:40
【问题描述】:

如何让 JPA 在 OneToMany 关系的 Many 一侧强制执行复合唯一约束的唯一值?

在下面的代码中,我有一个Person 实体,它有一个内部id,还有一组外部复合orgids,用于识别patient 与其他组织的关系.这些外部复合 id 由一个 root 组件和一个 extension 组件组成,该组件标识特定的 organization,该组件标识由 root 标识的特定 organization 内的 person。因此,root/extension 的组合在与每个person 关联的orgids 集合中必须是唯一的。如何设置代码来完成此操作?

下面的代码不断尝试在person_org_id table 中插入冗余的root/extension 值,尽管由于下面的 DDL 中的唯一约束,MySQL 数据库拒绝了这些插入尝试。

@Entity
@Table(name = "person")
public class Person {
    @Id
    @Column(name = "id")
    public Integer id;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
    private Set<PersonID> orgids;

    //other properties, then 
    //getters and setters
}

@Entity
@Table(name = "person_org_id",
uniqueConstraints={@UniqueConstraint(columnNames = {"id_root", "id_extension"})})
public class PersonID {
    @Id
    @Column(name = "id")
    public int id;

    @ManyToOne
    @JoinColumn(name = "person_id")
    private Person person;

    @NotNull
    @ManyToOne
    @JoinColumn(name="id_root")
    private Organization org;

    @NotNull
    @Column(name="id_extension")
    private String orgpersonid;

    //getters and setters
}


CREATE TABLE IF NOT EXISTS person(
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY 
  # , other fields
)engine=InnoDB;SHOW WARNINGS;

CREATE TABLE IF NOT EXISTS person_org_id(
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  person_id int(11) UNSIGNED NOT NULL,
  id_root varchar(100),
  id_extension varchar(100),
  CONSTRAINT UniqueRootExtKey UNIQUE (id_root, id_extension),
  FOREIGN KEY (person_id) REFERENCES person(id),
  FOREIGN KEY (id_root) REFERENCES organization(root)
)engine=InnoDB;SHOW WARNINGS;

CREATE TABLE IF NOT EXISTS organization(
  root varchar(100) NOT NULL PRIMARY KEY,
  name varchar(200)
)engine=InnoDB;SHOW WARNINGS;

这是一个使用 hibernate 和 jpa 的 spring mvc 应用程序。

【问题讨论】:

  • 我承认我的 JPA 有点生疏了(在我当前的长期项目中,我们只使用 JDBC CallableStatements 来对抗存储过程),但你不想要 OneToOne 关系吗?不过,也许我只是误读了这个问题。
  • @Powerlord 在OneToOne 关系中仍然允许Set 或orgids 吗? person 将在其 orgids 集中有多个条目,但 orgids 集中的每个成员必须是 root/extension 的唯一组合,以反映多个不同的 organizations,每个都有自己唯一的复合标识符用于相同的person。

标签: java spring hibernate spring-mvc jpa


【解决方案1】:

本质上,PersonID 表本身并不是一个实体,而是 Person 和 Organization 之间的链接表。您可以将此关联映射为 Hibernate/JPA 中的 Map,使用(在人员方面)组织作为键,扩展作为值。 (您也可以在组织端进行映射,扩展名作为键)

但是,在 PersonID 表上维护 PK 会很困难。然而,这个字段似乎是多余的。您可以删除它并添加通常用于映射映射表的约束。

在您的情况下,我将创建一个类结构,其中人具有 Map。这将映射为@ElementCollection,@CollectionTable 用于 PersonID 表,@MapKeyJoinColumn 参考组织表。这样,PersonID 就没有生成的 ID 列。 PK 将是对 Person 和 Organization 的两个 FK 列的约束。您可以将 Fk 上的唯一约束添加到 Organization 和 extension 列,以确保没有重复的 id。

或者,您可以将 PersonID 维护为实体,它们存储在地图中,并在 Map 和 PersonID.organization 属性上使用与 Person 和 map MapKey 的双向关联。但是你必须非常确定哪一边是读写的(控制),哪一边是只读的(反向)。不必要地更复杂。

【讨论】:

  • 感谢您抽出宝贵时间回答我的问题。我不明白你在暗示什么。您愿意发布建议的代码吗?这将帮助我理解你的想法。
  • 请参阅此处的第 7.2.2.2 节 docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch07.html 并阅读我的编辑。
  • 感谢您,感谢您抽出宝贵时间开始详细说明。我在您发送的链接中查看了第 7.2.2.2 节中的示例 7.11,但我无法具体看到如何更改我的代码。这些概念对我来说很难,答案还不直观。你愿意告诉我如何专门修复我的代码吗?这将有助于我理解这些概念。
猜你喜欢
  • 2022-01-11
  • 2016-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-03
  • 2011-07-12
  • 2016-11-21
  • 1970-01-01
相关资源
最近更新 更多