Hibernate Core Reference Manual学习笔记——Chapter 4. Persistent Classes

Chapter 4. Persistent Classes
Table of Contents
4.1. A simple POJO example
4.1.1. Implement a no-argument constructor
4.1.2. Provide an identifier property
4.1.3. Prefer non-final classes (semi-optional)
4.1.4. Declare accessors and mutators for persistent fields (optional)
4.2. Implementing inheritance
4.3. Implementing equals() and hashCode()
4.4. Dynamic models
4.5. Tuplizers
4.6. EntityNameResolvers

如果你的持久类遵循一些简单的规则(POJO编程模型),Hibernate将会很好的工作。但是,这并不是必须的。事实上,Hibernate并没有对你的持久类做过多的假定。你可以用其他的方式来表示你的领域模型(比如说用java.util.Map的实例)
4.1. A simple POJO example
Example 4.1. Simple POJO representing a cat

package eg;
import java.util.Set;
import java.util.Date;

public class Cat {
private Long id; // identifier

private Date birthdate;
private Color color;
private char sex;
private float weight;
    private int litterId;

    private Cat mother;
    private Set kittens = new HashSet();

    private void setId(Long id) {
        this.xml:id=id;
    }
    public Long getId() {
        return id;
    }

    void setBirthdate(Date date) {
        birthdate = date;
    }
    public Date getBirthdate() {
        return birthdate;
    }

    void setWeight(float weight) {
        this.weight = weight;
    }
    public float getWeight() {
        return weight;
    }

    public Color getColor() {
        return color;
    }
    void setColor(Color color) {
        this.color = color;
    }

    void setSex(char sex) {
        this.sex=sex;
    }
    public char getSex() {
        return sex;
    }

    void setLitterId(int id) {
        this.litterId = id;
    }
    public int getLitterId() {
        return litterId;
    }

    void setMother(Cat mother) {
        this.mother = mother;
    }
    public Cat getMother() {
        return mother;
    }
    void setKittens(Set kittens) {
        this.kittens = kittens;
    }
    public Set getKittens() {
        return kittens;
    }

    // addKitten not needed by Hibernate
    public void addKitten(Cat kitten) {
        kitten.setMother(this);
    kitten.setLitterId( kittens.size() );
        kittens.add(kitten);
    }
}

 
持久类需要遵循的四个主要规则如下:
4.1.1. Implement a no-argument constructor
实现一个无参的构造函数。这样,Hibernate才可以使用java.lang.reflect.Constructor.newInstance()实例化持久类。建议构造函数的可见性最小要和包的可见性一致,这是为了运行时代理生成能够正确工作。


4.1.2. Provide an identifier property
在Hibernate以前的版本中,这一项被视为可选的。至今也不是强制性的,但是最好将其视为deprecated功能,因为在即将发布的新版中,必须要提供一个identifier property。

标识属性并不非要在数据库中对应主键,只需对应可以唯一区别每一行的列即可。

我们建议你在持久化类中声明名字一致的标识属性并使用可空类型(也就是非原始类型)

4.1.3. Prefer non-final classes (半可选)

Hibernate很重要的一项功能proxies (延迟加载)的前提条件是持久类既不是final的也没有实现接口(声明的全是public方法的接口)。你可以用Hibernate持久化一个final类(没有实现接口),但是你将无法使用延迟加载,这将会影响应用程序的性能。为了持久化一个final类(没有实现"full"接口),你必须关闭proxy generation.如下:
Example 4.2. Disabling proxies in hbm.xml

<class name="Cat" lazy="false"...>...</class>

 
Example 4.3. Disabling proxies in annotations

@Entity @Proxy(lazy=false) public class Cat { ... }

 
如果final类实现了合适的接口,你还可以通知Hibernate在生成proxies时使用它的接口。
Example 4.4. Proxying an interface in hbm.xml

<class name="Cat" proxy="ICat"...>...</class>

 
Example 4.5. Proxying an interface in annotations

@Entity @Proxy(proxyClass=ICat.class) public class Cat implements ICat { ... }

 
你应该避免声明public final方法,因为这会限制从该类中生成proxies 。如果你想要使用的类中包含public final方法,你必须明确的关闭proxying。

许多其他的ORM工具直接持久化实例变量。但是为类的内部数据提供一个间接地访问会更好。默认情况下,Hibernate持久化JavaBeans形式的属性通过识别getFoo, isFoo 和setFoo这种形式的方法名。如果有必要,你可以切换到对某些特定的类属性进行直接访问。没有必要将类属性声明为public的。Hibernate同样可以持久化访问权限为 package, protected 或者 private 的类属性。

4.2. Implementing inheritance

子类也必须遵守第一条和第二条规则。例:

package eg;

public class DomesticCat extends Cat {
        private String name;

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

 

4.3. Implementing equals() and hashCode()

如果你想要:
将实例放到Set中去并且想要使用游离态实例的reattachment。
那么你不得不重写equals() 和 hashCode()方法。
Hibernate只能在一个特定的Session scope中保证persistent identity (database row)与 Java identity的相等性。当你把从不同的session中检索出来的的实例混合到一起,而又想它们的集合Set有意义,那么你必须重写 equals()和hashCode()。
实现 equals()/hashCode()最简单的方式就是比较对象的identifier。如果值相等,那么他们就代表数据库的同一行。如果它们都被添加到Set中去,那么Set当中实际只包含一个元素。不幸的是,当使用generated identifiers时,你不能使用该方式。因为只有当对象是持久态时,Hibernate才会分配identifier,一个新创建的实例还没有identifier。此外,如果一个实例没有保存并且存在于一个Set当中,保存Set时,Hibernate会给该实例一个identifier。

如果equals() 和hashCode()基于identifier的值,hash code会改变,打破Set的约定。到Hibernate网站查看对这一问题的详细讨论。这不是Hibernate的问题,而是正常的Java对于对象同一性和相等性的语义。
建议你使用Business key相等来实现equals() 和hashCode()。Business key相等意味着 equals() 方法只比较由business key构成的属性。它可以用来在现实世界当中区分我们的实例。例:

public class Cat {

    ...
    public boolean equals(Object other) {
        if (this == other) return true;
        if ( !(other instanceof Cat) ) return false;

        final Cat cat = (Cat) other;

        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
        if ( !cat.getMother().equals( getMother() ) ) return false;

        return true;
    }

    public int hashCode() {
        int result;
        result = getMother().hashCode();
        result = 29 * result + getLitterId();
        return result;
    }

}

 
business key不一定非要是数据库的主键。不可变或者唯一键都可以作为business key。

4.4. Dynamic models
Note
The following features are currently considered experimental and may change in the near future.
4.5. Tuplizers
4.6. EntityNameResolvers(以后看)

猜你喜欢

转载自soloplayer.iteye.com/blog/1758694
今日推荐