4.1 简单的POJO例子 我们将会在下面的章节中详细的描述持久化类的四个重要规则 4.1.1实现一个无参构造方法 Cat 类有一个无参的构造方法。所以的持久化类必须有一个默认的构造器(可以不是public的)因此,Hibernate可以通过反射(java.lang.reflect.Constructor.newInstance())来实例化他们。 推荐定义这个构造器的可见性至少为package 以便让运行时代理能够正常的工作。 4.1.2 提供一个唯一标示属性 注意:这个是推荐的,但是到现在都没有强制要求。这一条将会弃用,因为在将来的版本中将会强制要求提供一个唯一标示属性。Cat 有一个id属性。 这个属性对应底层数据库重的主键列。 唯一标示的数据类型可以是任意的“基本”数据类型。 更多的复合主键参照9.4 联合标示主键。 注意:不需要在数据表中单独为主键创建一个列, 他们只要是可以唯一的标示这行数据在基本表中的唯一性即可。 我们推荐在持久化类中使用命名一致的标示属性, 可以把它定义为一个可以为Null的类型(例如, 非原始数据类型) 4.1.3推荐使用非final的类(可选) Hibernate的一个重要的特性 ,代理(懒加载),依赖于非final的或者是一些实现了最只定义了public方法的接口的持久化类。你可以使用hibernate持久化一个没有继承任何借口的类,但是这就导致你不能使用延迟关联抓取的代理,这最终会限制了你在性能调优方面的选择。如果要持久化一个只实现了一个接口部分方法的类, 你必须禁用代理生成。参考示例4.2, 4.3 Example 4.2 通过hbm.xml 禁用代理应该避免声明public final 方法, 否则将会限制你使用该类来产生代理。如果你想要使用一个带有public final方法的类, 你必须明确的禁止使用代理。 参考示例4.2 和4.3。
4.1.4 为持久化字段声明函数(可选) Cat 类为他的每一个持久化字段都声明了存取方法。 许多其他的ORM工具直接持久化实例变量。 比较好的做法是在关系模式和类的内部数据结构之间提供一个桥梁。默认情况下, Hibernate 持久化JavaBean 识别格式为getFoo, isFoo和setFoo 的方法和属性。 如果有需要, 一些特别的属性你可以直接访问字段。 属性字段不需要一定是public的。Hibernate可以一样持久化可见性为package,protected, 或者private的字段。4.2 实现继承 一个子类也必须遵守第一和第二规则。它从父类继承唯一标示属性。 如Cat.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 实现equals() 和hashCode() 意图把持久化类的实例存放在Set中(描述多值关联的推荐的方式); 并且 意图使用游离的实例。Hibernate只在特定的session范围保证持久化身份和Java身份的一致性。当你在不同的session中混合检索实例,如果你希望保证Sets是有意义的,那么你必须实现equals()和hashCode()方法。 最简单的方法是实现equals()和hashCode()方法来比较来比较两个对象间的标示符的值。如果值相同,那么这两个对象在一定在数据库中对应相同的数据行, 因为他们是相同的。 如果两个都加入了Set集合,那么set集合中只会包含一个实例。不幸的是,对于自动生成的标示符不可以使用这种方法,因为Hibernate只会为持久化的对象分配标示符, 对于一个新产生的实例不会包含标示符值。如果equals()和hashCode()基于标示符,哈希码将会改变, 打破了Set集合的约束。可以在Hibernate的网站中查看针对该问题的更多的讨论内容, 这不是Hibernate的问题, 而是普通的对象的一致性与相等行的Java语义问题。 推荐使用业务键值的相等性来实现equals()和hashCode()方法。业务键值相等意思是在equals方法中之比较有关业务的属性值。 这个关键值可以在现实世界中唯一标示一个实例(一个自然的候选关键字): 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; } }一个业务关键字不一定是固定的候选主键(参考13.1.3章节)。不变的或者独一无二的属性都是很好的业务关键字的候选。 4.4 动态模型 注意: 下面的特性是实验性的,在将来会有所改变。在运行时持久化实体不是必须要被表示为一个POJO类或者JavaBean对象。Hibernate也支持动态模型。 使用这种方法,你不需要写持久化类,只需要映射文件。 默认情况下, Hibernate在普通的POJO模式下工作。你可以使用default_entity_mode配置选项,为特定的SessionFactory设置 默认的实体表示模型(参考3.3 “Hibernate 配置属性”, default_entity_mode选项可以不用配置,session可以自己判断 )。 下面的示例演示了使用MapS表示模型。首先, 在映射文件中需要声明entity-name来替换类名, 或者除了类名之外还要声明entity-name: <hibernate-mapping>
<class entity-name="Customer">
<id name="id"
type="long"
column="ID">
<generator class="sequence"/>
</id>
<property name="name"
column="NAME"
type="string"/>
<property name="address"
column="ADDRESS"
type="string"/>
<many-to-one name="organization"
column="ORGANIZATION_ID"
class="Organization"/>
<bag name="orders"
inverse="true"
lazy="false"
cascade="all">
<key column="CUSTOMER_ID"/>
<one-to-many class="Order"/>
</bag>
</class>
</hibernate-mapping> 虽然是用目标类名来声明冠梁的,但是关联的目标类型除了是POJO之外,也可以是一个动态的实体。 在你给SessionFactory设置默认的实体模型为dynamic-map之后, 在运行时你可以使用Maps: Session s = openSession(); Transaction tx = s.beginTransaction(); // Create a customer Map david = new HashMap(); david.put("name", "David"); // Create an organization Map foobar = new HashMap(); foobar.put("name", "Foobar Inc."); // Link both david.put("organization", foobar); // Save both s.save("Customer", david); s.save("Organization", foobar); tx.commit(); s.close(); 动态映射的好处是,变化所需要的时间少了, 因为圆形不需要实现实体类, 然而, 你无法进行编译期的类型检查, 并可能由此会处理很多的运行期异常。 幸亏有了Hibernate映射, 他使得数据库的schema可以容易的规格化和合理化, 并允许稍后再此之上添加合适的领域模型实现。 实体表示模式也能在每个Session的基础上设置: Session dynamicSession = pojoSession.getSession(EntityMode.MAP);//getSession(EntityMode mode)方法没找到。
// Create a customer
Map david = new HashMap();
david.put("name", "David");
dynamicSession.save("Customer", david);
...
dynamicSession.flush();
dynamicSession.close()
...
// Continue on pojoSession 注意:使用的EntityModel调用getSession()是在Session的API中,而不是SessionFactory。 这样新的额Session共享底层的JDBC链接, 事务,和其他的上下文信息。这意味着你不需要再第二个Session中调用flush()和close(),同样的, 把事务和链接的处理交给原来的工作单元。 4.5 元组片段映射 |
|
来自: Joselyn_cui > 《Hibernate》