如何制作复合主键(java持久性注释)

如何使表user_roles将两列(userID,roleID)定义为复合主键。 应该很容易,只是记不住/找不到。

user实体中:

 @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "user_roles") public List getRoles() { return roles; } @Id @GeneratedValue(strategy = GenerationType.AUTO) public Integer getUserID() { return userID; } 

roles实体中:

 @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "user_roles") public List getUsers() { return users; } @Id @GeneratedValue(strategy = GenerationType.AUTO) public Integer getRoleID() { return roleID; } 

谢谢。

** 更多信息

因此,第三个表user_roles (由上面自动生成)从user实体获取userID ,从roles实体获取roleID 。 现在我需要生成的表( user_roles )中的这两列作为复合主键。

你已经在这里找到了一些关于如何完全按照你的要求做出的好答案。

作为参考,我只想提一下在Hibernate中这样做的推荐方法,即使用代理键作为主键,并将业务键标记为NaturalId:

虽然我们建议使用代理键作为主键,但您应该尝试识别所有实体的自然键。 自然键是属性或属性的组合,它们是唯一且非空的。 它也是不可改变的。 映射元素内的自然键的属性。 Hibernate将生成必要的唯一键和可空性约束,因此,您的映射将更加自我记录。

建议您实现equals()和hashCode()以比较实体的自然键属性。

在代码中,使用注释,这看起来像这样:

 @Entity public class UserRole { @Id @GeneratedValue private long id; @NaturalId private User user; @NaturalId private Role role; } 

使用它可以为您节省很多麻烦,因为您会发现您经常需要引用/映射组合主键。

我发现这很难,最后只是放弃了与Hibernate的斗争,而是决定顺其自然。 我完全理解在您的情况下这可能是不可能的,因为您可能正在处理遗留软件或依赖项,但我只是想提及它以供将来参考。 ( 如果你不能使用它也许别人可以 !)

为了满足您的要求,您可以将@ManyToMany映射为@OneToMany映射。 这样,USER_ROLE将包含USER_ID和ROLE_ID作为复合主键

我会告诉你如何:

 @Entity @Table(name="USER") public class User { @Id @GeneratedValue private Integer id; @OneToMany(cascade=CascadeType.ALL, mappedBy="joinedUserRoleId.user") private List joinedUserRoleList = new ArrayList(); // no-arg required constructor public User() {} public User(Integer id) { this.id = id; } // addRole sets up bidirectional relationship public void addRole(Role role) { // Notice a JoinedUserRole object JoinedUserRole joinedUserRole = new JoinedUserRole(new JoinedUserRole.JoinedUserRoleId(this, role)); joinedUserRole.setUser(this); joinedUserRole.setRole(role); joinedUserRoleList.add(joinedUserRole); } } @Entity @Table(name="USER_ROLE") public class JoinedUserRole { public JoinedUserRole() {} public JoinedUserRole(JoinedUserRoleId joinedUserRoleId) { this.joinedUserRoleId = joinedUserRoleId; } @ManyToOne @JoinColumn(name="USER_ID", insertable=false, updatable=false) private User user; @ManyToOne @JoinColumn(name="ROLE_ID", insertable=false, updatable=false) private Role role; @EmbeddedId // Implemented as static class - see bellow private JoinedUserRoleId joinedUserRoleId; // required because JoinedUserRole contains composite id @Embeddable public static class JoinedUserRoleId implements Serializable { @ManyToOne @JoinColumn(name="USER_ID") private User user; @ManyToOne @JoinColumn(name="ROLE_ID") private Role role; // required no arg constructor public JoinedUserRoleId() {} public JoinedUserRoleId(User user, Role role) { this.user = user; this.role = role; } public JoinedUserRoleId(Integer userId, Integer roleId) { this(new User(userId), new Role(roleId)); } @Override public boolean equals(Object instance) { if (instance == null) return false; if (!(instance instanceof JoinedUserRoleId)) return false; final JoinedUserRoleId other = (JoinedUserRoleId) instance; if (!(user.getId().equals(other.getUser().getId()))) return false; if (!(role.getId().equals(other.getRole().getId()))) return false; return true; } @Override public int hashCode() { int hash = 7; hash = 47 * hash + (this.user != null ? this.user.hashCode() : 0); hash = 47 * hash + (this.role != null ? this.role.hashCode() : 0); return hash; } } } 

记得

如果对象具有指定的标识符或复合键,则在调用save()之前,应该将标识符分配给对象实例。

所以我们创建了一个像这样的JoinedUserRoleId构造函数来处理它

 public JoinedUserRoleId(User user, Role role) { this.user = user; this.role = role; } 

最后是Role类

 @Entity @Table(name="ROLE") public class Role { @Id @GeneratedValue private Integer id; @OneToMany(cascade=CascadeType.ALL, mappedBy="JoinedUserRoleId.role") private List joinedUserRoleList = new ArrayList(); // no-arg required constructor public Role() {} public Role(Integer id) { this.id = id; } // addUser sets up bidirectional relationship public void addUser(User user) { // Notice a JoinedUserRole object JoinedUserRole joinedUserRole = new JoinedUserRole(new JoinedUserRole.JoinedUserRoleId(user, this)); joinedUserRole.setUser(user); joinedUserRole.setRole(this); joinedUserRoleList.add(joinedUserRole); } } 

根据测试,让我们写下面的内容

 User user = new User(); Role role = new Role(); // code in order to save a User and a Role Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Serializable userId = session.save(user); Serializable roleId = session.save(role); session.getTransaction().commit(); session.clear(); session.close(); // code in order to set up bidirectional relationship Session anotherSession = HibernateUtil.getSessionFactory().openSession(); anotherSession.beginTransaction(); User savedUser = (User) anotherSession.load(User.class, userId); Role savedRole = (Role) anotherSession.load(Role.class, roleId); // Automatic dirty checking // It will set up bidirectional relationship savedUser.addRole(savedRole); anotherSession.getTransaction().commit(); anotherSession.clear(); anotherSession.close(); 

请注意根据以上代码无参考JoinedUserRole类。

如果要检索JoinedUserRole,请尝试以下操作

 Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Integer userId; Integer roleId; // Lets say you have set up both userId and roleId JoinedUserRole joinedUserRole = (JoinedUserRole) session.get(JoinedUserRole.class, new JoinedUserRole.JoinedUserRoleId(userId, roleId)); // some operations session.getTransaction().commit(); session.clear(); session.close(); 

问候,

复合键是使用@IdClass完成的(另一种方式是使用@EmbeddedId和@Embeddable,不确定你要查找哪一个)@IdClass如下

 @Entity @IdClass(CategoryPK.class) public class Category { @Id protected String name; @Id protected Date createDate; } public class CategoryPK implements Serializable { String name; Date createDate; public boolean equals(object other) { //implement a equals that the PP can use to determine //how the CategoryPK object can be identified. } public int hashCode(){ return Super.hashCode(); } } 

我的类别将是您的user_roles,名称和createDate将是您的用户ID和角色

感谢您改进您的问题……并考虑到这些建议。

(对不起,你用Daos后缀你的实体有点奇怪,但这不是重点。)

我不确定还有什么问题:

  • 您描述的两个实体都有一个PK,而不是一对。
  • 链接表没有对应的实体,它由两个实体及其ManyToMany关系隐含地定义。 如果您需要第三个实体,请更改您的ManyToMany以获得一对OneToMany和ManyToOne关系。

我对主键有同样的问题。 我也知道@Embeddable和@EmbeddedId类的解决方案。 但我只想要带注释的简单解决方案。

我通过这篇文章找到了启示: http //www.vaannila.com/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html

这是魔术:

这会在连接表上生成主键:

 @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name="classA_classB") private Set classesA; 

这不会在连接表上生成主键:

 @ManyToMany(cascade = CascadeType.ALL) @JoinTable(name="classA_classB") private List classesA; 

至少在我的环境中

请注意,区别在于使用SetList