Introduction
Sometime you need several column for you primary keys. The background for that can very. There are two solution for that in JPA:
@IdClass
as inline columns@EmbeddedId
with extract column in separate class
Databas Design
_____________ | | | Student | |_____________| | | | *studentId | | *groupId | | firstName | | | |_____________|
@IdClass
@Entity
@IdClass(StudentPK.class)
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private Long studentId;
@Id
private Long groupId;
// the rest is left out for brevity
}
public class StudentPK implements Serializable {
private static final long serialVersionUID = 1L;
private Long studentId;
private Long groupId;
@Override
public int hashCode() {
return (int) (studentId + groupId);
}
@Override
public boolean equals(Object object) {
if (object instanceof StudentPK) {
StudentPK otherId = (StudentPK) object;
return (otherId.studentId == this.studentId)
&& (otherId.groupId == this.groupId);
}
return false;
}
public Long getStudentId() {
return studentId;
}
public void setStudentId(Long studentId) {
this.studentId = studentId;
}
public Long getGroupId() {
return groupId;
}
public void setGroupId(Long groupId) {
this.groupId = groupId;
}
}
@EmbeddedId
@Entity
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private StudentPK studentPK;
// the rest is left out for brevity
}
The StudentPK
class remains the same.
Conclusion
The two above option is very much the same and I cannot see any clear advantage for one solution over the other, so I would recommend use the solution that resembles the real world, i.e. SQL and use IdClass
.
Automatic Generated Values
When having composite primary key you cannot use @GeneratedValue
, but you can use @TableGenerator
. Remember there are three strategies for automatic primary key generation values and the only database vendor neutral solution is TABLE
.
@GeneratedValue(strategy = IDENTITY)
, with automatic generated value on column. Works only for MySQL and MS SQL.@GeneratedValue(strategy = SEQUENCE)
, separate sequence. Works only for PostgreSQL and Oracle.@GeneratedValue(strategy = TABLE)
, the ONLY database vendor neutral solution. ORM specific implementation, does not rely on any database specific technique. Uses separate table to persist increment value and handles increment by it self.
@Entity
@IdClass(StudentPK.class)
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@TableGenerator(name = "TABLE_STUDENT_GEN", table = "SEQ_TABLE", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "STUDENT_SEQ")
@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_STUDENT_GEN")
@Column(unique = true)
private Long studentId;
@Id
@TableGenerator(name = "TABLE_GROUP_GEN", table = "SEQ_TABLE", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "GROUP_SEQ")
@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GROUP_GEN")
private Long groupId;
// the rest is left out for brevity
}
The StudentPK
class remains the same.
Which will generate the following database.
_____________ _____________ | | | | | Student | | SEQ_TABLE | |_____________| |_____________| | | | | | *studentId | | SEQ_NAME | | *groupId | | SEQ_COUNT | | firstName | | | |_____________| |_____________|
NOTE You do not need to have automatic generated values for both columns.
NOTE You do not need to have unique
constraint for id column, I just added it to show that you can, because sometimes you want to have it.
No comments:
Post a Comment