Ch10 advanced object relational mapping - skatscher/pro_jpa2_book GitHub Wiki

Table and Column Names

  • SQL standard defines that undelimited database identifiers do not respect case
  • If some database names are intended to be case-specific, they must be explicitly delimited (by ")
@Table(name="\"Employee\"")
@Table(name="\"EMPLOYEE\"")

Complex Embedded Objects

Advanced Embedded Mappings

  • Embedded objects can embed other objects, have element collections of basic or embeddable types, as well as have relationships to entities.
  • Example
@Embeddable @Access(AccessType.FIELD)
public class ContactInfo {
  @Embedded
  private Address residence;

  @ManyToOne
  @JoinColumn(name="PRI_NUM")
  private Phone primaryPhone;

  @ManyToMany @MapKey(name="type")
  @JoinTable(name="EMP_PHONES")
  private Map<String, Phone> phones;
}

@Entity
public class Phone {
  @Id String num;

  @ManyToMany(mappedBy="contactInfo.phones")
  List<Employee> employees;

  String type;
}
  • Note:
    • default join column would be EMPLOYEE_PHONE
    • mappedBy element uses the qualified name of the embedded relationship attribute (".")

Overriding Embedded Relationships

  • The embedding entity can override mappings by using @AttributeOverride to redefine how the embedded state is mapped within the particular entity table
  • To override how a relationship is mapped we need to use @AssociationOverride, which provides us with the ability to override relationship join columns and join tables.
  • Example:
@Entity
public class Customer {
  @Id int id;
  @Embedded
  @AttributeOverride(name="address.zip", column=@Column(name="ZIP"))
  @AssociationOverrides({
    @AssociationOverride(name="primaryPhone", joinColumns=@JoinColumn(name="EMERG_PHONE")),
    @AssociationOverride(name="phones", joinTable=@JoinTable(name="CUST_PHONE"))})
  private ContactInfo contactInfo;
}

Compound Primary Keys

  • primary key is composed of multiple fields/columns
  • primary key class: must include definitions for equals() and hashCode(), fields and properties must be in the set of valid identifiers, public, implement Serializable, have a no-arg constructor

Id Class

@Entity
@IdClass(EmployeeId.class)
public class Employee {
  @Id 
  private String country;
  @Id
  @Column(name="EMP_ID")
  private int id;
  //...
}

public class EmployeeId implements Serializable {
  private String country;
  private int id;
  
  public EmployeeId() {}
  
  public EmployeeId(String country, int id) {
    this.country = country;
    this.id = id;
  }

  public String getCountry() { return country; }
  public int getId() { return id; }

  public boolean equals(Object o) {
    return ((o instanceof EmployeeId) &&
    country.equals(((EmployeeId)o).getCountry()) &&
      id == ((EmployeeId)o).getId());
  }

  public int hashCode() {
    return country.hashCode() + id;
  }
}
  • Note: there are no setter methods, since primary key values can't be changed, after they have been constructed.
  • Invoking:
EmployeeId empId = new EmployeeId(country, empId);
Employee emp = em.find(Employee.class, empId);
⚠️ **GitHub.com Fallback** ⚠️