hibernate Composite Primary Key Annotation

Keywords: Attribute Java Hibernate Database

Three approaches are provided in the documentation of the Hibernate annotation specification:
1. Annotate the component class as @Embeddable and the attribute of the component as @Id.

 2. Annotate the attribute of the component as @Embeddable;
    package com.cmh.beans;

import javax.persistence.Embeddable;
import java.io.Serializable;

@Embeddable
public class TestPK implements Serializable {

  private static final long serialVersionUID = 7935499208104916305L;

  private String firstName;

  private String lastName; 

  public TestPK() { 
  } 

  public String getFirstName() { 
    return firstName; 
  } 

  public void setFirstName(String firstName) { 
    this.firstName = firstName; 
  } 

  public String getLastName() { 
    return lastName; 
  } 

  public void setLastName(String lastName) { 
    this.lastName = lastName; 
  } 

  @Override 
  public boolean equals(Object obj) {

    if(this == obj) return true;
    if(obj == null) return false;
    if(!(obj instanceof TestKey)) return false;
    TestPK objKey = (TestPK)obj;
    if(firstName.equalsIgnoreCase(objKey.firstName) &&
            lastName.equalsIgnoreCase(objKey.lastName)) {
      return true;
    }
    return false;
  } 

  @Override 
  public int hashCode() {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + (firstName == null ? 0 : firstName.hashCode());
    result = PRIME * result + (lastName == null ? 0 : lastName.hashCode());
    return result;
  } 
} 

Main class

package com.cmh.beans;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
* Created by mianhai on 2017/2/16.
*/
@Entity
@Table
public class EmbeddableTest {
@EmbeddedId
private TestPK id;

private String name;

public EmbeddableTest() {
}


@Column(name = "firstname")
public String getFirstName(){
    return id.getFirstName();
}

@Column(name = "lastname")
public String getLastName(){
    return id.getLastName();
}

@Column(name = "name")
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

It's important to note that fields such as @Column(name = lastname) and @Column (compound primary key) are also written in the entity class.
@Column(name = "firstname")
Instead of defining column names in TestPK, you can use the following methods for common composite primary keys
The @AttributeOverride annotation specifies the first Name of the Test class, and lastName maps to the first_name and last_name of the tables in the database.
The following code is in class Test
@EmbeddedId
@AttributeOverrides( {
@AttributeOverride(name = firstName, column = @Column(name = first_name)),
@AttributeOverride(name = lastName, column = @Column(name = last_name)) })

  1. Annotate the class as @IdClass, and annotate all primary key attributes in the entity as @Id.
    Here, I use the third method - @IdClass. Here is the specific code. Let's discuss it together.

    First of all, it needs to be noted that the @IdClass approach requires the establishment of a primary key class based on all the primary key attributes, which contains all the primary keys, and, as a primary key class, the following requirements need to be met:

    1. Primary key classes must implement implements Serializable.
    2. Primary key classes must have default public parameter-free construction methods.
    3. Primary key classes must override equals and hashCode methods.
      The code is as follows:

Our PK

package com.cmh.beans;

import java.io.Serializable;

/**
 * Created by mianhai on 2017/2/15.
 */
public class TestKey implements Serializable{

    private static final long serialVersionUID = 6811601262303871530L;

    // key attribute
    private String ip;

    // key attribute
    private String examPlaceId;

    // key attribute
    private String examId;

    /**
     * A parametric public construction method must have
     */
    public TestKey() {

    }

    /**
     * Rewriting a construction method with parameters
     * @param ip
     * @param examPlaceId
     * @param examId
     */
    public TestKey(String ip, String examPlaceId, String examId) {
        this.ip = ip;
        this.examId = examId;
        this.examPlaceId = examPlaceId;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getExamPlaceId() {
        return examPlaceId;
    }

    public void setExamPlaceId(String examPlaceId) {
        this.examPlaceId = examPlaceId;
    }

    public String getExamId() {
        return examId;
    }

    public void setExamId(String examId) {
        this.examId = examId;
    }

    public static long getSerialversionuid() {
        return serialVersionUID;
    }

    /**
     * To override hashCode methods, you must have
     */
    @Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = PRIME * result + (ip == null ? 0 : ip.hashCode());
        result = PRIME * result + (examId == null ? 0 : examId.hashCode());
        result = PRIME * result + (examPlaceId ==null ? 0 : examPlaceId.hashCode());
        return result;
    }

    /**
     * To cover equals methods, you must have
     */
    @Override
    public boolean equals(Object obj) {
        if(this == obj) return true;
        if(obj == null) return false;
        if(!(obj instanceof TestKey)) return false;
        TestKey objKey = (TestKey)obj;
        if(ip.equalsIgnoreCase(objKey.ip) &&
                examId.equalsIgnoreCase(objKey.examId) &&
                examPlaceId.equalsIgnoreCase(objKey.examPlaceId)) {
            return true;
        }
        return false;
    }
}

Main class

package com.cmh.beans;

import javax.persistence.*;

/**
 * Created by mianhai on 2017/2/15.
 */
@Entity
@Table(name="TE_IPMap")
@IdClass(TestKey.class)
public class ComponetIDKey {
    // Primary key, where you need to add the @Id tag
    @Id
    @Column(name="IP")
    private String ip;

    @Column(name="StudentNo")
    private String studentNo;

    // Primary key, where you need to add the @Id tag
    @Id
    @Column(name="ExamPlaceId")
    private String examPlaceId;

    // Primary key, where you need to add the @Id tag
    @Id
    @Column(name="ExamId", unique=true)
    private String examId;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getStudentNo() {
        return studentNo;
    }

    public void setStudentNo(String studentNo) {
        this.studentNo = studentNo;
    }

    public String getExamPlaceId() {
        return examPlaceId;
    }

    public void setExamPlaceId(String examPlaceId) {
        this.examPlaceId = examPlaceId;
    }

    public String getExamId() {
        return examId;
    }

    public void setExamId(String examId) {
        this.examId = examId;
    }
}

The generated sql is as follows:

create table te_ipmap (exam_id varchar(255) not null, exam_place_id varchar(255) not null, ip varchar(255) not null, student_no varchar(255), primary key (exam_id, exam_place_id, ip))

In the primary key class, in order for the class in the collection framework (such as HashMap) to work properly, the equals and hashCode methods must be overridden at the same time, and this method should not be overloaded because of the wrong parameter type, but not overridden.
Overwriting equals always overrides hashCode, a common source of error is that hashCode methods are not overridden. In each class that overrides the equals method, the hashCode method must also be overridden. Failure to do so violates the general convention of Object.hashCode, which prevents the class from working together with all hash-based collections, including HashMap, HashSet, and Hashtable.
—— From Effective Java

Posted by dreams4000 on Mon, 01 Apr 2019 00:54:30 -0700