Hibernate3.2 中文版参考手册
2007/01/04 15:00
2006/11/02 22:57
设计细颗粒度的持久类并且使用<component>来实现映射。
使用一个Address持久类来封装 street, suburb, state, postcode. 这将有利于代码重用和简化代码重构(refactoring)的工作。
对持久类声明标识符属性( identifier properties)。
Hibernate中标识符属性是可选的,不过有很多原因来说明你应该使用标识符属性。我们建议标识符应该是“人造”的(自动生成,不涉及业务含义)。
使用自然键(natural keys)标识
对所有的实体都标识出自然键,用<natural-id>进行映射。实现equals()和hashCode(),在其中用组成自然键的属性进行比较。
为每个持久类写一个映射文件
不要把所有的持久类映射都写到一个大文件中。把 com.eg.Foo 映射到com/eg/Foo.hbm.xml中, 在团队开发环境中,这一点显得特别有意义。
把映射文件作为资源加载
把映射文件和他们的映射类放在一起进行部署。
考虑把查询字符串放在程序外面
如果你的查询中调用了非ANSI标准的SQL函数,那么这条实践经验对你适用。把查询字符串放在映射文件中可以让程序具有更好的可移植性。
使用绑定变量
就像在JDBC编程中一样,应该总是用占位符"?"来替换非常量值,不要在查询中用字符串值来构造非常量值!更好的办法是在查询中使用命名参数。
不要自己来管理JDBC connections
Hibernate允许应用程序自己来管理JDBC connections,但是应该作为最后没有办法的办法。如果你不能使用Hibernate内建的connections providers,那么考虑实现自己来实现org.hibernate.connection.ConnectionProvider
考虑使用用户自定义类型(custom type)
假设你有一个Java类型,来自某些类库,需要被持久化,但是该类没有提供映射操作需要的存取方法。那么你应该考虑实现org.hibernate.UserType接口。这种办法使程序代码写起来更加自如,不再需要考虑类与Hibernate type之间的相互转换。
使用一个Address持久类来封装 street, suburb, state, postcode. 这将有利于代码重用和简化代码重构(refactoring)的工作。
对持久类声明标识符属性( identifier properties)。
Hibernate中标识符属性是可选的,不过有很多原因来说明你应该使用标识符属性。我们建议标识符应该是“人造”的(自动生成,不涉及业务含义)。
使用自然键(natural keys)标识
对所有的实体都标识出自然键,用<natural-id>进行映射。实现equals()和hashCode(),在其中用组成自然键的属性进行比较。
为每个持久类写一个映射文件
不要把所有的持久类映射都写到一个大文件中。把 com.eg.Foo 映射到com/eg/Foo.hbm.xml中, 在团队开发环境中,这一点显得特别有意义。
把映射文件作为资源加载
把映射文件和他们的映射类放在一起进行部署。
考虑把查询字符串放在程序外面
如果你的查询中调用了非ANSI标准的SQL函数,那么这条实践经验对你适用。把查询字符串放在映射文件中可以让程序具有更好的可移植性。
使用绑定变量
就像在JDBC编程中一样,应该总是用占位符"?"来替换非常量值,不要在查询中用字符串值来构造非常量值!更好的办法是在查询中使用命名参数。
不要自己来管理JDBC connections
Hibernate允许应用程序自己来管理JDBC connections,但是应该作为最后没有办法的办法。如果你不能使用Hibernate内建的connections providers,那么考虑实现自己来实现org.hibernate.connection.ConnectionProvider
考虑使用用户自定义类型(custom type)
假设你有一个Java类型,来自某些类库,需要被持久化,但是该类没有提供映射操作需要的存取方法。那么你应该考虑实现org.hibernate.UserType接口。这种办法使程序代码写起来更加自如,不再需要考虑类与Hibernate type之间的相互转换。
2006/11/02 22:57
本章展示了一些较为复杂的关系映射。
23.1. Employer(雇主)/Employee(雇员)
下面关于Employer 和 Employee的关系模型使用了一个真实的实体类 (Employment)来表述,这是因为对于相同的雇员和雇主可能会有多个雇佣时间段。 对于金额和雇员姓名,用Components建模。
映射文件可能是这样:
<hibernate-mapping>
<class name="Employer" table="employers">
<id name="id">
<generator class="sequence">
<param name="sequence">employer_id_seq</param>
</generator>
</id>
<property name="name"/>
</class>
<class name="Employment" table="employment_periods">
<id name="id">
<generator class="sequence">
<param name="sequence">employment_id_seq</param>
</generator>
</id>
<property name="startDate" column="start_date"/>
<property name="endDate" column="end_date"/>
<component name="hourlyRate" class="MonetaryAmount">
<property name="amount">
<column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
</property>
<property name="currency" length="12"/>
</component>
<many-to-one name="employer" column="employer_id" not-null="true"/>
<many-to-one name="employee" column="employee_id" not-null="true"/>
</class>
<class name="Employee" table="employees">
<id name="id">
<generator class="sequence">
<param name="sequence">employee_id_seq</param>
</generator>
</id>
<property name="taxfileNumber"/>
<component name="name" class="Name">
<property name="firstName"/>
<property name="initial"/>
<property name="lastName"/>
</component>
</class>
</hibernate-mapping>
用SchemaExport生成表结构。
23.1. Employer(雇主)/Employee(雇员)
下面关于Employer 和 Employee的关系模型使用了一个真实的实体类 (Employment)来表述,这是因为对于相同的雇员和雇主可能会有多个雇佣时间段。 对于金额和雇员姓名,用Components建模。
映射文件可能是这样:
<hibernate-mapping>
<class name="Employer" table="employers">
<id name="id">
<generator class="sequence">
<param name="sequence">employer_id_seq</param>
</generator>
</id>
<property name="name"/>
</class>
<class name="Employment" table="employment_periods">
<id name="id">
<generator class="sequence">
<param name="sequence">employment_id_seq</param>
</generator>
</id>
<property name="startDate" column="start_date"/>
<property name="endDate" column="end_date"/>
<component name="hourlyRate" class="MonetaryAmount">
<property name="amount">
<column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
</property>
<property name="currency" length="12"/>
</component>
<many-to-one name="employer" column="employer_id" not-null="true"/>
<many-to-one name="employee" column="employee_id" not-null="true"/>
</class>
<class name="Employee" table="employees">
<id name="id">
<generator class="sequence">
<param name="sequence">employee_id_seq</param>
</generator>
</id>
<property name="taxfileNumber"/>
<component name="name" class="Name">
<property name="firstName"/>
<property name="initial"/>
<property name="lastName"/>
</component>
</class>
</hibernate-mapping>
用SchemaExport生成表结构。
2006/11/02 22:56
22.1. 持久化类
下面的持久化类表示一个weblog和在其中张贴的一个贴子。他们是标准的父/子关系模型,但是我们会用一个有序包(ordered bag)而非集合(set)。
[codes=java]
package eg;
import java.util.List;
public class Blog {
private Long _id;
private String _name;
private List _items;
public Long getId() {
return _id;
}
public List getItems() {
return _items;
}
public String getName() {
return _name;
}
public void setId(Long long1) {
_id = long1;
}
public void setItems(List list) {
_items = list;
}
public void setName(String string) {
_name = string;
}
}
package eg;
import java.text.DateFormat;
import java.util.Calendar;
public class BlogItem {
private Long _id;
private Calendar _datetime;
private String _text;
private String _title;
private Blog _blog;
public Blog getBlog() {
return _blog;
}
public Calendar getDatetime() {
return _datetime;
}
public Long getId() {
return _id;
}
public String getText() {
return _text;
}
public String getTitle() {
return _title;
}
public void setBlog(Blog blog) {
_blog = blog;
}
public void setDatetime(Calendar calendar) {
_datetime = calendar;
}
public void setId(Long long1) {
_id = long1;
}
public void setText(String string) {
_text = string;
}
public void setTitle(String string) {
_title = string;
}
}
[/codes]
22.2. Hibernate 映射
下面的持久化类表示一个weblog和在其中张贴的一个贴子。他们是标准的父/子关系模型,但是我们会用一个有序包(ordered bag)而非集合(set)。
[codes=java]
package eg;
import java.util.List;
public class Blog {
private Long _id;
private String _name;
private List _items;
public Long getId() {
return _id;
}
public List getItems() {
return _items;
}
public String getName() {
return _name;
}
public void setId(Long long1) {
_id = long1;
}
public void setItems(List list) {
_items = list;
}
public void setName(String string) {
_name = string;
}
}
package eg;
import java.text.DateFormat;
import java.util.Calendar;
public class BlogItem {
private Long _id;
private Calendar _datetime;
private String _text;
private String _title;
private Blog _blog;
public Blog getBlog() {
return _blog;
}
public Calendar getDatetime() {
return _datetime;
}
public Long getId() {
return _id;
}
public String getText() {
return _text;
}
public String getTitle() {
return _title;
}
public void setBlog(Blog blog) {
_blog = blog;
}
public void setDatetime(Calendar calendar) {
_datetime = calendar;
}
public void setId(Long long1) {
_id = long1;
}
public void setText(String string) {
_text = string;
}
public void setTitle(String string) {
_title = string;
}
}
[/codes]
22.2. Hibernate 映射
2006/11/02 22:55
刚刚接触Hibernate的人大多是从父子关系(parent / child type relationship)的建模入手的。父子关系的建模有两种方法。由于种种原因,最方便的方法是把Parent和Child都建模成实体类,并创建一个从Parent指向Child的<one-to-many>关联,对新手来说尤其如此。还有一种方法,就是将Child声明为一个<composite-element>(组合元素)。 事实上在Hibernate中one to many关联的默认语义远没有composite element贴近parent / child关系的通常语义。下面我们会阐述如何使用带有级联的双向一对多关联(bidirectional one to many association with cascades)去建立有效、优美的parent / child关系。这一点也不难!
21.1. 关于collections需要注意的一点
Hibernate collections被当作其所属实体而不是其包含实体的一个逻辑部分。这非常重要!它主要体现为以下几点:
当删除或增加collection中对象的时候,collection所属者的版本值会递增。
如果一个从collection中移除的对象是一个值类型(value type)的实例,比如composite element,那么这个对象的持久化状态将会终止,其在数据库中对应的记录会被删除。同样的,向collection增加一个value type的实例将会使之立即被持久化。
另一方面,如果从一对多或多对多关联的collection中移除一个实体,在缺省情况下这个对象并不会被删除。这个行为是完全合乎逻辑的--改变一个实体的内部状态不应该使与它关联的实体消失掉!同样的,向collection增加一个实体不会使之被持久化。
实际上,向Collection增加一个实体的缺省动作只是在两个实体之间创建一个连接而已,同样移除的时候也只是删除连接。这种处理对于所有的情况都是合适的。对于父子关系则是完全不适合的,在这种关系下,子对象的生存绑定于父对象的生存周期。
21.2. 双向的一对多关系(Bidirectional one-to-many)
假设我们要实现一个简单的从Parent到Child的<one-to-many>关联。
<set name="children">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
如果我们运行下面的代码
Parent p = .....;
Child c = new Child();
p.getChildren().add(c);
session.save(c);
session.flush();
Hibernate会产生两条SQL语句:
一条INSERT语句,为c创建一条记录
一条UPDATE语句,创建从p到c的连接
这样做不仅效率低,而且违反了列parent_id非空的限制。我们可以通过在集合类映射上指定not-null="true"来解决违反非空约束的问题:
<set name="children">
<key column="parent_id" not-null="true"/>
<one-to-many class="Child"/>
</set>
然而,这并非是推荐的解决方法。
21.1. 关于collections需要注意的一点
Hibernate collections被当作其所属实体而不是其包含实体的一个逻辑部分。这非常重要!它主要体现为以下几点:
当删除或增加collection中对象的时候,collection所属者的版本值会递增。
如果一个从collection中移除的对象是一个值类型(value type)的实例,比如composite element,那么这个对象的持久化状态将会终止,其在数据库中对应的记录会被删除。同样的,向collection增加一个value type的实例将会使之立即被持久化。
另一方面,如果从一对多或多对多关联的collection中移除一个实体,在缺省情况下这个对象并不会被删除。这个行为是完全合乎逻辑的--改变一个实体的内部状态不应该使与它关联的实体消失掉!同样的,向collection增加一个实体不会使之被持久化。
实际上,向Collection增加一个实体的缺省动作只是在两个实体之间创建一个连接而已,同样移除的时候也只是删除连接。这种处理对于所有的情况都是合适的。对于父子关系则是完全不适合的,在这种关系下,子对象的生存绑定于父对象的生存周期。
21.2. 双向的一对多关系(Bidirectional one-to-many)
假设我们要实现一个简单的从Parent到Child的<one-to-many>关联。
<set name="children">
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
如果我们运行下面的代码
Parent p = .....;
Child c = new Child();
p.getChildren().add(c);
session.save(c);
session.flush();
Hibernate会产生两条SQL语句:
一条INSERT语句,为c创建一条记录
一条UPDATE语句,创建从p到c的连接
这样做不仅效率低,而且违反了列parent_id非空的限制。我们可以通过在集合类映射上指定not-null="true"来解决违反非空约束的问题:
<set name="children">
<key column="parent_id" not-null="true"/>
<one-to-many class="Child"/>
</set>
然而,这并非是推荐的解决方法。



下载文件



