Using a composite key in a many-to-many relationship in JPA
I've got the following situation:
- A User object has a Set of Permission objects (
Set<Permission>
) - Each User can have zero or more Permissions
- A Permission object has three fields
- The three fields of Permission make up the composite key for that permission.
- 开发者_如何学GoAs a consequence of this, we want exactly one instance in the DB of each Permission. Each user can potentially have the same Permission.
- The User object therefore has a many-to-many relationship with Permission.
The question is: how, in this situation, do I make the Permission entity a composite key of itself? I'm particularly interested in doing this in the context of this many-to-many relationship.
Any ideas?
1º A Permission object has three fields
2º The three fields of Permission up make up the composite key
Both property and compound primary keys share the same columns
So Your question looks like this one
@Entity
public class Permission {
private PermissionId permissionId;
private Integer field1;
private Integer field2;
private Integer field3;
// required no-arg constructor
public Permission() {}
public Permission(Integer field1, Integer field2, Integer field3) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
setPermissionId(new PermissonId(Integer field1, Integer field2, Integer field3));
}
@EmbeddedId
public PermissionId getPermissionId() {
return this.permissionId;
}
@Column(name="FIELD_1", insertable=false, updatable=false)
public Integer getField1() {
return this.field1;
}
@Column(name="FIELD_2", insertable=false, updatable=false)
public Integer getField2() {
return this.field2;
}
@Column(name="FIELD_3", insertable=false, updatable=false)
public Integer getField3() {
return this.field3;
}
@Embeddable
public static class PermissionId implements Serializable {
private Integer field1;
private Integer field2;
private Integer field3;
// required no-arg constructor
public PermissionId() {}
public PermissionId(Integer field1, Integer field2, Integer field3) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
}
@Column(name="FIELD_1", nullable=false)
public Integer getField1() {
return this.field1;
}
@Column(name="FIELD_2", nullable=false)
public Integer getField2() {
return this.field2;
}
@Column(name="FIELD_3", nullable=false)
public Integer getField3() {
return this.field3;
}
public boolean equals(Object o) {
if(o == null)
return false;
if(!(o instanceof PermissionId))
return false;
final PermissionId other = (PermissionId) o;
if(!(getField1().equals(other.getField1())))
return false;
if(!(getField2().equals(other.getField2())))
return false;
if(!(getField3().equals(other.getField3())))
return false;
return true;
}
// requered hashcode impl
public int hashcode() {
// code goes here
}
}
}
But do not forget
Because more than one property share the same column, you have to define one of them as insertable=false, updatable=false. Otherwise, Hibernate will complain some errors.
And
When you have a compound primary key, you have to set up its values. Hibernate does not support automatic generation of compound primary key.
But if you do not like the approach as shown above, you can do the following one
@Entity
@IdClass(PermissionId.class)
public class Permission {
private Integer field1;
private Integer field2;
private Integer field3;
// required no-arg constructor
public Permission() {}
public Permission(Integer field1, Integer field2, Integer field3) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
}
@Id
@Column(name="FIELD_1", nullable=false)
public Integer getField1() {
return this.field1;
}
@Id
@Column(name="FIELD_2", nullable=false)
public Integer getField2() {
return this.field2;
}
@Id
@Column(name="FIELD_3", nullable=false)
public Integer getField3() {
return this.field3;
}
@Embeddable
public static class PermissionId implements Serializable {
private Integer field1;
private Integer field2;
private Integer field3;
// required no-arg constructor
public PermissionId() {}
public PermissionId(Integer field1, Integer field2, Integer field3) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
}
@Column(name="FIELD_1")
public Integer getField1() {
return this.field1;
}
@Column(name="FIELD_2")
public Integer getField2() {
return this.field2;
}
@Column(name="FIELD_3")
public Integer getField3() {
return this.field3;
}
public boolean equals(Object o) {
if(o == null)
return false;
if(!(o instanceof PermissionId))
return false;
final PermissionId other = (PermissionId) o;
if(!(getField1().equals(other.getField1())))
return false;
if(!(getField2().equals(other.getField2())))
return false;
if(!(getField3().equals(other.getField3())))
return false;
return true;
}
// requered hashcode impl
public int hashcode() {
// code goes here
}
}
}
regards,
精彩评论