主键为多个字段的映射问题

来源:互联网 发布:道教佛教 知乎 编辑:程序博客网 时间:2024/05/16 08:11

在同常情况下,Hibernate建议为持久化类定义一个标识属性,用于唯一地标识某个持久化实例。

对于主键只有一个字段的情况来说,用@Id进行标识就行了,此处不多说。

问题是当标识属性对应多个字段时,该怎么办呢?

组件作为符合主键

使用组件作为复合主键,也就是使用组件作为持久化类的标识符,则该组件类必须满足以下要求:
1. 有无参的构造函数。
2. 必须实现java.io.Serializable接口。
3. 建议正确地重写equals()和hashCode()方法,也就是根据组件类的关键属性来区分组件对象。

当使用组件作为复合主键时,Hibernate无法为这种复合主键生成主键值,所以程序必须为持久化实例分配这种组件标识符(即它不像id一样指定生成的策略之后就可以自动的生成对应的值,需要我们手动的赋值给它)。

下面看一个组件类的例子:

// 1. 实现Serializable接口public class Name implements Serializable{    private String first;    private String last;    // 2. 无参的构造函数    public Name() {    }    public Name(String first, String last) {        this.first = first;        this.last = last;    }    // 3. 重写equals()和hashCode()方法    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Name name = (Name) o;        if (first != null ? !first.equals(name.first) : name.first != null) return false;        return !(last != null ? !last.equals(name.last) : name.last != null);    }    @Override    public int hashCode() {        int result = first != null ? first.hashCode() : 0;        result = 31 * result + (last != null ? last.hashCode() : 0);        return result;    }}

当持久化类使用组件作为复合主键时,程序需要使用@EmbededId来修饰该主键。@EmbededId和@Embeded的用法基本相似,只是@Embeded用于修饰普通的组件属性,而@EmbededId用于修饰组件类型的主键。

下面的Person类将使用一个Name类型的主键:

public class Person {    // 以Name组件作为标识属性    @EmbeddedId    @AttributeOverrides({        // 指定        @AttributeOverride(name="first",                column = @Column(name = "person_firstname")),        @AttributeOverride(name="last",                column = @Column(name = "person_lastname"))    })    private Name name;    private Integer age;    // 省略下面的getter、setter,构造器什么的}

上面Person的标识属性不再是基本类型,也不是String字符串,而是Name类型。Name类型是用户自定义的组件类型,因此程序使用了@EmbeddedId修饰该复合主键,并使用@AttributeOverride定义组件内各属性与底层数据列之间的映射。

多列作为联合主键

Hibernate还提供了另一种联合主键支持,Hibernate允许直接将持久化类的多个属性映射成联合主键。不过得满足以下条件:
1. 有无参的构造函数。
2. 实现java.io.Serializable接口。
3. 建议正确地重写equals()和hashCode()方法。

将持久化类的多个属性映射为联合主键非常简单,直接使用多个@Id修饰这些属性即可。

public class Person implements Serializable {    // 定义first属性, 作为标识属性的成员    private String first;    // 定义last属性, 作为标识属性的成员    private String last;    private Integer age;    // 省略下面的代码    // 重写equals和hashCode方法    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Person person = (Person) o;        if (first != null ? !first.equals(person.first) : person.first != null) return false;        if (last != null ? !last.equals(person.last) : person.last != null) return false;        return !(age != null ? !age.equals(person.age) : person.age != null);    }    @Override    public int hashCode() {        int result = first != null ? first.hashCode() : 0;        result = 31 * result + (last != null ? last.hashCode() : 0);        result = 31 * result + (age != null ? age.hashCode() : 0);        return result;    }}

程序使用Person类的两个属性作为联合主键,因此Person类需要实现Serializable接口。对于Person的实例,first和last组合起来能唯一标识该实例。

0 0