6.3.4.主键类和复合类
有时关系映射要求一个主键由多个持久化属性复合而成,例如,我们的关系模型明确指明实体Customer的唯一标识通过
last name和安全码代替自动生成的数字键.这些被称作复合主键.Java持久化规范提供了多种途径映射这种类型的模型。
其中的一种是通过@javax.persistence.IdClass.注释;其它的是通过@javax.persistence.EmbeddedId注释.
6.3.4.1. @IdClass 注释
第一种方法定义主键类(和复合主键)使用@IdClass注释.组件类不用使用主键在其中.但是不使用它来与实体管理器
交互当查找一个持久化对象通过它的主键.@IdClass是类级的注释并且指定那个键类将被使用当与实体管理器交互时.
@Target(TYPE)
@Retention(RUNTIME)
public @interface IdClass
{
Class value( );
}
在你的组件类中,你指明一个或多个属性做为主键,使用@ID注释.这些属性将映射, 成准确的属性在@IdClass.
让我们看以下将Customer组件类改成复合主键为name和安全码.首先,让我们定义一个主键类:
package com.titan.domain;
public class CustomerPK
implements java.io.Serializable {
private String lastName;
private long ssn;
public CustomerPK( ) {}
public CustomerPK(String lastName, long ssn)
{
this.lastName = lastName;
this.ssn = ssn;
}
public String getLastName( ) { return this.lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public long getSsn( ) { return ssn; }
public void setSsn(long ssn) { this.ssn = ssn; }
public boolean equals(Object obj)
{
if (obj == this) return true;
if (!(obj instanceof CustomerPK)) return false;
CustomerPK pk = (CustomerPK)obj;
if (!lastName.equals(pk.lastName)) return false;
if (ssn != pk.ssn) return false;
return true;
}
public int hashCode( )
{
return lastName.hashCode( ) + ssn.hashcode;
}
}
主键类必需满足下列条件:
※必需被序列化
※必需有一个公共的无参构造方法
※必需实现equals()和hashCode()方法
Customer组件必需有同样要求的属性同CustomerPK类的属性被加上@Id注释的.
package com.titan.domain;
import javax.persistence.*;
@Entity
@IdClass(CustomerPK.class)
public class Customer implements java.io.Serializable {
private String firstName;
private String lastName;
private long ssn;
public String getFirstName( ) { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
@Id
public String getLastName( ) { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
@Id
public long getSsn( ) { return ssn; }
public void setSsn(long ssn) { this.ssn = ssn; }
}
注意:主键自动生成不支持复合键和主键类.你需要手工创建键值.
让我们看一下等价的XML文件:
<entity-mappings>
<entity class="com.titan.domain.Customer" access="PROPERTY">
<id-class>com.titan.domain.CustomerPK</id-class>
<attributes>
<id name="lastName"/>
<id name="ssn"/>
</attributes>
</entity>
</entity-mappings>
<id-class>元素是<entity>的子元素,并且它的值是完全有资格做主键类的类名,注意,多个<id>元素映射成主键类.
主键类用于当你查询Customer组件时:
CustomerPK pk = new CustomerPK("Burke", 9999999);
Customer cust = entityManager.find(Customer.class, pk);
无论你何时调用EntityManager的方法像find()或getreference(),你必需使用主键类才能识别这个实体.
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((cnincd == null) ? 0 : cnincd.hashCode());
- result = prime * result + ((nedityp == null) ? 0 : nedityp.hashCode());
- result = prime * result + ((kaishacd == null) ? 0 : kaishacd.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- final MEditypPK other = (MEditypPK) obj;
- if (cnincd == null) {
- if (other.cnincd != null)
- return false;
- } else if (!cnincd.equals(other.cnincd))
- return false;
- if (nedityp == null) {
- if (other.nedityp != null)
- return false;
- } else if (!nedityp.equals(other.nedityp))
- return false;
- if (kaishacd == null) {
- if (other.kaishacd != null)
- return false;
- } else if (!kaishacd.equals(other.kaishacd))
- return false;
- return true;
- }