Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate composite primary key using @Embedded and @Id

I wanted to find out if hibernate supports composite primary key using a field and a component type. So I have an @Embeddable component type and I would like to use it as a primary key along with another column as a composite primary key.

So my table "DEPT_HISTORY" has composite primary keys (GROUP_DEPT, DEPTID, EFFDT). I mapped GROUP_DEPT and DEPTID as an @Embeddable component type to Department class.

@Embeddable public class Department implements Serializable {

    private static final long serialVersionUID = 1L;

    private String departmentGroup;

    private String departmentId;

    public String getDepartmentGroup() {
        return departmentGroup;
    }

    public void setDepartmentGroup(String departmentGroup) {
        this.departmentGroup = departmentGroup;
    }

    public Department withDepartmentGroup(String departmentGroup) {
        setDepartmentGroup(departmentGroup);
        return this;
    }

    public String getDepartmentId() {
        return departmentId;
    }

    public void setDepartmentId(String departmentId) {
        this.departmentId = departmentId;
    }

    public Department withDepartmentId(String departmentId) {
        setDepartmentId(departmentId);
        return this;
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this).add("departmentGroup", getDepartmentGroup())
                .add("departmentId", getDepartmentId()).toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof Department)) {
            return false;
        }
        Department other = (Department) obj;

        return Objects.equal(getDepartmentGroup(), other.getDepartmentGroup())
                && Objects.equal(getDepartmentId(), other.getDepartmentId());

    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getDepartmentGroup(), getDepartmentId());
    }

}

I am mapping a composite primary key using GROUP_DEPT, DEPTID above and EFFDT below as follows. Does hibernate support this. I have similar classes that it works on but for some reason fails on this class with "Caused by: org.hibernate.AnnotationException: com.blah.blah.component.Department must not have @Id properties when used as an @EmbeddedId: com.blah.blah.entity.DepartmentHistory.department

@Entity @Table(name = "dept_history") public class DepartmentHistory implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final String DATETIME_FORMAT = "MM-dd-yyyy HH:mm:ss ZZ";
    protected static final DateTimeFormatter DATE_FORMAT = DateTimeFormat.forPattern(DATETIME_FORMAT);

    @Id
    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name = "departmentGroup", column = @Column(name = "GROUP_DEPT", nullable = false)),
            @AttributeOverride(name = "departmentId", column = @Column(name = "DEPTID", nullable = false)) })
    private Department department;

    @Id
    @Column(name = "EFFDT", nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar effectiveDate;

    @Column(name = "DESCR", nullable = false)
    private String description;

    @Column(name = "MANAGER_ID", nullable = false)
    private String managerId;

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(final Department department) {
        this.department = department;
    }

    public DepartmentHistory withDepartment(final Department department) {
        setDepartment(department);
        return this;
    }

    public Calendar getEffectiveDate() {
        return effectiveDate;
    }

    public void setEffectiveDate(final Calendar effectiveDate) {
        this.effectiveDate = effectiveDate;
    }

    public DepartmentHistory withEffectiveDate(final Calendar effectiveDate) {
        setEffectiveDate(effectiveDate);
        return this;
    }

    public DateTime readEffectiveDateAsDateTime() {
        return calendarToDateTime(effectiveDate);
    }

    public void writeEffectiveDateAsDateTime(final DateTime effectiveDate) {
        this.effectiveDate = dateTimeToCalendar(effectiveDate);
    }

    public DepartmentHistory withEffectiveDateAsDateTime(final DateTime effectiveDate) {
        writeEffectiveDateAsDateTime(effectiveDate);
        return this;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(final String description) {
        this.description = description;
    }

    public DepartmentHistory withDescription(final String description) {
        setDescription(description);
        return this;
    }

    public String getManagerId() {
        return managerId;
    }

    public void setManagerId(final String managerId) {
        this.managerId = managerId;
    }

    public DepartmentHistory withManagerId(final String managerId) {
        setManagerId(managerId);
        return this;
    }

    @Override
    public String toString() {
        return Objects.toStringHelper(this).add("department", getDepartment())
                .add("effectiveDate", DATE_FORMAT.print(readEffectiveDateAsDateTime()))
                .add("description", getDescription()).add("managerId", getManagerId()).toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof DepartmentHistory)) {
            return false;
        }
        DepartmentHistory other = (DepartmentHistory) obj;

        return Objects.equal(getDepartment(), other.getDepartment())
                && Objects.equal(getEffectiveDate(), other.getEffectiveDate());

    }

    @Override
    public int hashCode() {
        return Objects.hashCode(getDepartment(), getEffectiveDate());
    }

}

Can I combine an @Embeddable and another field into a composite primary key using @Id property on the @Embedded and field. I don't want to make (GROUP_DEPT, DEPTID, EFFDT) as an @EmbeddedId because such a component type does not make sense and I don't want to create a class that does not mean anything in my domain just to use as a composite primary key. A component Department containing just (GROUP_DEPT, DEPTID) makes sense as a department. Thanks much.

like image 482
user290870 Avatar asked Feb 25 '14 04:02

user290870


1 Answers

As per the spec you should use and @EmbeddedId or @IdClass when you use composite key.

If the dependent entity class has primary key attributes in addition to those corresponding to the parent's primary key or if the parent has a composite primary key, an embedded id or id class must be used to specify the primary key of the dependent entity. It is not necessary that parent entity and dependent entity both use embedded ids or both use id classes to represent composite primary keys when the parent has a composite key.

Question was:

I am mapping a composite primary key using GROUP_DEPT, DEPTID above and EFFDT below as follows. Does hibernate support this.?

Yes hibernate support that, but you should use @EmbeddedId, I know that this need to create a new class to handle the key but that need to be done as far as I know.

like image 161
Koitoer Avatar answered Nov 07 '22 08:11

Koitoer