}
被动方(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 如下: