如何制作复合主键(java持久化注解)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1212058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to make a composite primary key (java persistence annotation)
提问by b0x0rz
How to make it so that the table user_roles defines the two columns (userID, roleID) as a composite primary key. should be easy, just can't remember/find.
如何使表user_roles 定义两列(userID、roleID)作为复合主键。应该很容易,只是不记得/找不到。
In user
entity:
在user
实体中:
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles")
public List<RoleDAO> getRoles() {
return roles;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getUserID() {
return userID;
}
In roles
entity:
在roles
实体中:
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "user_roles")
public List<UserDAO> getUsers() {
return users;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getRoleID() {
return roleID;
}
Thank you.
谢谢你。
** MORE INFO
** 更多信息
So there is a third table user_roles
(auto generated by above) that takes userID
from user
entity and roleID
from roles
entity. Now I need those two columns in the generated table (user_roles
) to be a composite primary key.
因此,有一个第三表user_roles
即花费(由上述自动生成)userID
从user
实体和roleID
从roles
实体。现在我需要生成的表 ( user_roles
)中的这两列作为复合主键。
采纳答案by Tim
You've already had a few good answers here on how to do exactly as you ask..
您已经在这里有了一些关于如何完全按照您的要求做的很好的答案..
For reference let me just mention the recommended way to do this in Hibernate instead, which is to use a surrogate key as primary key, and to mark business keys as NaturalId's:
作为参考,让我仅提及在 Hibernate 中执行此操作的推荐方法,即使用代理键作为主键,并将业务键标记为 NaturalId:
Although we recommend the use of surrogate keys as primary keys, you should try to identify natural keys for all entities. A natural key is a property or combination of properties that is unique and non-null. It is also immutable. Map the properties of the natural key inside the element. Hibernate will generate the necessary unique key and nullability constraints and, as a result, your mapping will be more self-documenting.
It is recommended that you implement equals() and hashCode() to compare the natural key properties of the entity.
尽管我们建议使用代理键作为主键,但您应该尝试为所有实体标识自然键。自然键是唯一且非空的属性或属性组合。它也是不可变的。映射元素内自然键的属性。Hibernate 将生成必要的唯一键和可空性约束,因此,您的映射将更加自我记录。
建议您实现 equals() 和 hashCode() 来比较实体的自然键属性。
In code, using annotations, this would look something like this:
在代码中,使用注释,这看起来像这样:
@Entity
public class UserRole {
@Id
@GeneratedValue
private long id;
@NaturalId
private User user;
@NaturalId
private Role role;
}
Using this will save you a lot of headaches down the road, as you'll find out when you frequently have to reference / map the composed primary key.
使用它可以为您省去很多麻烦,因为您会发现何时经常需要引用/映射组合主键。
I found this out the hard way, and in the end just gave up fighting against Hibernate and instead decided to go with the flow. I fully understand that this might not be possible in your case, as you might be dealing with legacy software or dependencies, but I just wanted to mention it for future reference. (if you can't use it maybe someone else can!)
我很艰难地发现了这一点,最后只是放弃了与 Hibernate 的斗争,而是决定顺其自然。我完全理解这在您的情况下可能是不可能的,因为您可能正在处理遗留软件或依赖项,但我只是想提及它以供将来参考。(如果您不能使用它,也许其他人可以!)
回答by KLE
Thank you for improving your question ... and taking into account the suggestions.
感谢您改进您的问题……并考虑了这些建议。
(Sorry, It is a bit strange that you postfix your entities with Daos, but it is not the point.)
(抱歉,你用 Daos 后缀你的实体有点奇怪,但这不是重点。)
I'm not sure there is any problem left :
我不确定还有什么问题:
- The two entities you describe each have one PK, not a pair-of.
- The link-table has no corresponding entity, it is defined implicitely by the two entities and their ManyToMany relationship. If you need a third Entity, change your ManyToMany for a pair of OneToMany and ManyToOne relationships.
- 您描述的两个实体各有一个 PK,而不是一对。
- 链接表没有对应的实体,它是由两个实体及其多对多关系隐式定义的。如果您需要第三个实体,请将 ManyToMany 更改为一对 OneToMany 和 ManyToOne 关系。
回答by OpenSource
Composite keys are done using @IdClass (the other way is using @EmbeddedId and @Embeddable not sure which one you are looking for) the @IdClass is as follows
复合键是使用@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();
}
}
my Category here will be your user_roles and the name and createDate will be your userid and roleid
my Category 将是您的 user_roles,名称和 createDate 将是您的 userid 和 roleid
回答by Arthur Ronald
In order to fulfill your requirement, you can map your @ManyToMany as a @OneToMany mapping. This way, USER_ROLE will contain both USER_ID and ROLE_ID as compound primary key
为了满足您的要求,您可以将@ManyToMany 映射为@OneToMany 映射。这样,USER_ROLE 将同时包含 USER_ID 和 ROLE_ID 作为复合主键
I will show you how to:
我将向您展示如何:
@Entity
@Table(name="USER")
public class User {
@Id
@GeneratedValue
private Integer id;
@OneToMany(cascade=CascadeType.ALL, mappedBy="joinedUserRoleId.user")
private List<JoinedUserRole> joinedUserRoleList = new ArrayList<JoinedUserRole>();
// 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;
}
}
}
remember
记住
If an object has an assigned identifier, or a composite key, the identifier SHOULD BE ASSIGNED to the object instance BEFORE calling save().
如果对象具有分配的标识符或复合键,则在调用 save() 之前,应将标识符分配给对象实例。
So we have created a JoinedUserRoleId constructor like this one in order to take care of it
所以我们创建了一个像这样的 JoinedUserRoleId 构造函数来处理它
public JoinedUserRoleId(User user, Role role) {
this.user = user;
this.role = role;
}
And finally Role class
最后角色类
@Entity
@Table(name="ROLE")
public class Role {
@Id
@GeneratedValue
private Integer id;
@OneToMany(cascade=CascadeType.ALL, mappedBy="JoinedUserRoleId.role")
private List<JoinedUserRole> joinedUserRoleList = new ArrayList<JoinedUserRole>();
// 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);
}
}
According to test it, let's write the following
根据测试一下,我们写如下
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();
Notice according to code above NO REFERENCE to JoinedUserRole class.
根据上面的代码注意没有对 JoinedUserRole 类的引用。
If you want to retrieve a JoinedUserRole, try the following
如果要检索 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();
regards,
问候,
回答by steveeen
I had the same Problem with the primary keys. I also knew the solution with the @Embeddable and @EmbeddedId Class. But i wanted just the simple solution with the annotations.
我对主键有同样的问题。我也知道@Embeddable 和@EmbeddedId 类的解决方案。但我只想要带有注释的简单解决方案。
Well i found enlightenment through this article:http://www.vaannila.com/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html
好吧,我通过这篇文章找到了启示:http : //www.vaannila.com/hibernate/hibernate-example/hibernate-mapping-many-to-many-using-annotations-1.html
and here is the magic:
这是魔法:
this generates a primary key on the join table:
这会在连接表上生成一个主键:
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="classA_classB")
private Set<ClassA> classesA;
this dosn't generate a primary key on the join table:
这不会在连接表上生成主键:
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name="classA_classB")
private List<ClassA> classesA;
at least in my enviroment
至少在我的环境中
Note that the difference is using Setor List
请注意,不同之处在于使用Set或List