• 沒有找到結果。

public Set getAddresses() { return addresses;

在文檔中 Hibernate 开发指南 (頁 41-45)

}

被动方(Taddress)的记录由 Hibernate 负责读取,之后存放在主控方指定的 Collection 类型属性中。

对 于 one-to-many 关 联 关 系 , 我 们 可 以 采 用 java.util.Set ( 或 者 net.sf.hibernate.collection.Bag)类型的 Collection,表现在 XML 映射文件 中也就是<set>…</set>(或<bag>…</bag>)节点。关于 Hibernate 的 Collection 实现,请参见 Hibernate Reference.

one-to-many 节点有以下属性:

属性 描述 类型 必须

cascade 操作级联(cascade)关系。

可选值:

all : 所有情况下均进行级联操作。

none:所有情况下均不进行级联操作。

save-update:在执行 save-update 时 进行级联操作。

delete:在执行 delete 时进行级联操作。

Text N

sort 排序类型。 Text N

可选值:

unsorted :不排序(默认)

natural :自然顺序(避免与 order-by 搭配使用)

comparatorClass :指以某个实现了 java.util.Comparator 接口的类作为排

outer-join

是否使用外联接。

true:总是使用 outer-join false:不使用 outer-join

auto(默认) :如果关联对象没有采用 Proxy 机制,则使用 outer-join.

Text N

batch-size

采用延迟加载特性时(Lazy Loading)

一次读入的数据数量。

Transaction tx = session.beginTransaction();

TAddress addr = new TAddress();

addr.setTel("1123");

addr.setZipcode("233123");

addr.setAddress("Hongkong");

user.getAddresses().add(addr);

session.save(user);//通过主控对象级联更新

tx.commit();

为了完成这个操作,Hibernate会分两步(两条SQL)来完成新增t_address 记录的操作:

1. save(user)时:

insert into t_address (user_id, address, zipcode, tel) values (null, "Hongkong", "233123", "1123")

2. tx.commit()时

update t_address set user_id= ”1”, address= "Hongkong", zipcode="233123", tel="1123" where id=2

第一条SQL用于插入新的地址记录。

第二条SQL用于更新t_address,将user_id设置为其关联的user对象的id值。

问题就出在这里,数据库中,我们的t_address.user_id字段为“NOT NULL”

型,当Hibernate执行第一条语句创建t_address记录时,试图将user_id字段的 值设为null,于是引发了一个约束违例异常:

net.sf.hibernate.PropertyValueException: not-null property references a null or transient value:

org.hibernate.sample.TAddress.userId

因为关联方向是单向,关联关系由TUser对象维持,而被关联的addr对象本身并 不知道自己与哪个TUser对象相关联,也就是说,addr对象本身并不知道user_id应 该设为什么数值。

因此,在保存addr时,只能先在关联字段插入一个空值。之后,再由TUser对象 将自身的id值赋予关联字段addr.user_id,这个赋值操作导致addr对象属性发生变 动,在事务提交时,hibernate会发现这一改变,并通过update sql将变动后的数 据保存到数据库。

第一个步骤中,企图向数据库的非空字段插入空值,因此导致了约束违例。

既然TUser对象是主控方,为什么就不能自动先设置好下面的TAddress对象的 关俩字段值再一次做Insert操作呢?莫名其妙?Ha,don’t ask me ,go to ask Hibernate TeamJ。

我们可以在设计的时候通过一些手段进行调整,以避免这样的约束违例,如将关

1.

insert into t_address (address, zipcode, tel) values ('Hongkong', '233123', '1123')

2.

update t_address set user_id=1 where id=7

生成第一条insert语句时,没有包含user_id字段,数据库会使用该字段的默

<class

① 这里与前面不同,inverse 被设为“true”,这意味着 TUser 不再作为主控方,

而是将关联关系的维护工作交给关联对象

org.hibernate.sample.TAddress

来 完成。这样 TAddress 对象在持久化过程中,就可以主动获取其关联的 TUser 对象的 id,

并将其作为自己的 user_id,之后执行一次 insert 操作即可完成全部工作。

在 one-to-many 关系中,将 many 一方设为主动方(inverse=false)将有助性能 的改善。(现实中也一样,如果要让胡锦涛记住全国人民的名字,估计花个几十年也 不可能,但要让全国人民知道胡锦涛,可就不需要那么多时间了。J)

对应的 xdoclet tag 如下:

public class TUser implements Serializable {

……

在文檔中 Hibernate 开发指南 (頁 41-45)

相關文件