14

我正在尝试优化我的@Entity课程。让我们以User <-> Group关系的常见情况为例。我还想存储建立关系的日期。表布局:

 USER      GROUP_USER      GROUP
------    ------------    -------
 id        user_id         id
 name      group_id        name
           createdAt

有以下3个类:

  1. User@OneToMany List<GroupUser>
  2. GroupUser@ManyToOne User和_@ManyToOne Group
  3. Group@OneToMany List<GroupUser>

它可以工作,但对于常见的用例来说很糟糕。例如:给我所有组User user

List<Group> groups;
for(GroupUser gu : user.getGroupUsers) {
    groups.add(gu.getGroup());
}

然后Map我想到了使用 a 的想法。所以我创建了以下 3 个类:

@Entity
class User {
   @Column(name="id")
   UUID id;

   @Column(name="name")
   String name;

   @ElementCollection
   @CollectionTable(name="Group_User")
   Map<Group, GroupUserRelationData> groups;
}

@Entity
class Group {
   @Column(name="id")
   UUID id;

   @Column(name="name")
   String name;

   @ElementCollection
   @CollectionTable(name="Group_User")
   Map<User, GroupUserRelationData> users;
}

@Embeddable
class GroupUserRelationData {
  @Column(name="createdAt")
  DateTime createdAt;
}

确实按预期创建了 3 个表,但表中的列Group_User很奇怪:

 USER      GROUP_USER      GROUP
------    ------------    -------
 id        User_id         id
 name      users_KEY       name
           Group_id
           group_KEY
           createdAt

我确定我遗漏了一些东西......看起来我必须指定 JoinColumn。但正确的方法是什么?

@CollectionTable(joinColumns=...)@MapKeyColumn和 和有什么区别@MapKeyJoinColumn。我必须设置所有这些吗?

还是我必须使用@ManyToMany而不是@ElementCollection

我只想获得与顶部相同的表格布局,使用java.util.Map.


编辑#1:此外,数据库之后应该对表有正确的约束:

  • 复合主键(Group_id、User_id)

目前它创建了一个复合 PK(Group_id,users_KEY),这对我来说似乎很奇怪。它还创建了 4(!!) 个索引,每列一个User_id、和。Group_idusers_KEYgroups_KEY


编辑#2:我找到了一个网站,它告诉何时使用哪些注释: http: //kptek.wordpress.com/2012/06/26/collection-mapping/

坏事是:我仍然不知道为什么......

解决方案:

经过一番尝试,我想出了以下代码,这正是我想要的。我必须使用所有这些注释,否则它会创建额外的列:

@Entity
class User {
   @Column(name="id")
   UUID id;

   @Column(name="name")
   String name;

   @ElementCollection
   @CollectionTable(name="Group_User",
     joinColumns=@JoinColumn(name="User_Id"))
   @MapKeyJoinColumn(name="Group_Id")
   Map<Group, GroupUserRelationData> groups;
}

@Entity
class Group {
   @Column(name="id")
   UUID id;

   @Column(name="name")
   String name;

   @ElementCollection
   @CollectionTable(name="Group_User",
     joinColumns=@JoinColumn(name="Group_Id"))
   @MapKeyJoinColumn(name="User_Id")
   Map<User, GroupUserRelationData> users;
}

@Embeddable
class GroupUserRelationData {
  @Column(name="createdAt")
  DateTime createdAt;
}

我仍然很想看到这些注释究竟做了什么的解释,以及为什么默认行为会创建四列和一个奇怪的主键。

4

1 回答 1

2

映射需要一对多键和映射键。

在您的第一个示例中,Hibernate 发现它需要一个 FKGroup.id来匹配GroupUser.group_id以加载关联的用户。但是因为您没有指定 Map 键,所以它必须弄清楚从哪里获取它

因此,Hibernate 假设您想要一个@MapKeyColumn,并且因为未指定列名,所以使用属性名称后跟下划线后跟 KEY(例如 users_KEY)。

这就是为什么你有这两个额外的列。当您提供 时@MapKeyJoinColumn(name="User_Id"),地图就知道从哪里获取密钥。

于 2014-06-27T10:47:24.130 回答