OMG,到底在寻找什么..................
(构造一个完美的J2EE系统所需要的完整知识体系)
posts - 198,  comments - 37,  trackbacks - 0

One-to-one 关系映射

 

    对于 hibernate one-to-one 关系来说,大家常常把它忽略,认为它很简单,其实这里面有些细节需要注意,在 hibernate3 中有两种实现one-to-one的方法:第一种就是用 many-to-one 来代替一对多,其实 one-to-one 也就是 many-to-one 的一种极限方式,若把 many-to-one 设置 unique="true" ,则这时候的 many-to-one 实质上就是 one-to-one; 这里为什么能够用 many-to-one 来代替 one-to-one 呢?最根本的是两个对象必须有一个字段相关联,那么你也发现 one-to-one 中没有 column 属性,也就是不能够把 one-to-one 的这种关系生成一个字段 / 属性,而 many-to-one 可以,它有 column 属性。所以,说了这么多,你应该明白为什么可以用 many-to-one 来代替 one-to-one.

 

对于这种方法要注意几点:

例如,下面的介绍中 use 中的两个字段同时影射 adress ,只能够实现单向 one-to-one, 也就是从 use adress ,不能够实现从 adress use. 然但下面也介绍了可以使用复杂的方法来解决,但是得不偿失。

 

第二种方法:基于主键关联的 one-to-one, 这种方法比较直接。也就是让 adress 的主键值和 use 的一样就可以了,通过

<id name="id" column="ADDRESS_ID">

<generator class="foreign">

<param name="property">user</param>

</generator>

来把 adress 的主键值和 use 的主键值相等。其余的设置都是小事。

 

对于初学者来说应该注意:单在 use adress 中设置 one-to-one 是不行的,需要设置上面的代码,需要实现one-to-one两端的对象主键值相同,这是最主要的。这也是 one-to-one many-to-one 的不同之处。应当注意。

                                                                                           fasttalk

                                                                               www.blogjava.net/asktalk

 

 

 

Using a foreign key association

The easiest way to represent the association from User to its billingAddress is to use a <many-to-one> mapping with a unique constraint on the foreign key. This may surprise you, since many doesn’t seem to be a good description of either end of a one-to-one association! However, from Hibernate’s point of view, there isn’t much difference between the two kinds of foreign key associations. So, we add a foreign key column named BILLING_ADDRESS_ID to the USER table and map it as follows:

 

<many-to-one name="billingAddress"

class="Address"

column="BILLING_ADDRESS_ID"

cascade="save-update"/>

 

Note that we’ve chosen save-update as the cascade style. This means the Address will become persistent when we create an association from a persistent User. Probably,  cascade="all" makes sense for this association, since deletion of the User should result in deletion of the Address. (Remember that Address now has its own entity lifecycle.)

 

Our database schema still allows duplicate values in the BILLING_ADDRESS_ID column of the USER table, so two users could have a reference to the same address. To make this association truly one-to-one, we add unique="true" to the <many-toone> element, constraining the relational model so that there can be only one user per address:

 

<many-to-one name="billingAddress"

class="Address"

column="BILLING_ADDRESS_ID"

cascade="all"

unique="true"/>

 

This change adds a unique constraint to the BILLING_ADDRESS_ID column in the DDL generated by Hibernate—resulting in the table structure illustrated by figure 6.7.

 

But what if we want this association to be navigable from Address to User in Java?  From chapter 3, you know how to turn it into a bidirectional one-to-many collection—but we’ve decided that each Address has just one User, so this can’t be the right solution. We don’t want a collection of users in the Address class. Instead, we add a property named user (of type User) to the Address class, and map it like so in the mapping of Address:

 

<one-to-one name="user"

class="User"

property-ref="billingAddress"/>

 

This mapping tells Hibernate that the user association in Address is the reverse direction of the billingAddress association in User.

 

In code, we create the association between the two objects as follows:

Address address = new Address();

address.setStreet("646 Toorak Rd");

address.setCity("Toorak");

address.setZipcode("3000");

Transaction tx = session.beginTransaction();

User user = (User) session.get(User.class, userId);

address.setUser(user);

user.setBillingAddress(address);

tx.commit();

image002.gif

To finish the mapping, we have to map the homeAddress property of User. This is easy enough: we add another <many-to-one> element to the User metadata, mapping a new foreign key column, HOME_ADDRESS_ID:

 

<many-to-one name="homeAddress"

class="Address"

column="HOME_ADDRESS_ID"

cascade="save-update"

unique="true"/>

 

The USER table now defines two foreign keys referencing the primary key of the ADDRESS table: HOME_ADDRESS_ID and BILLING_ADDRESS_ID.

 

Unfortunately, we can’t make both the billingAddress and homeAddress associations bidirectional, since we don’t know if a particular address is a billing address or a home address. (We can’t decide which property name—billingAddress or homeAddress—to use for the property-ref attribute in the mapping of the user property.) We could try making Address an abstract class with subclasses HomeAddress and BillingAddress and mapping the associations to the subclasses. This approach would work, but it’s complex and probably not sensible in this case.  Our advice is to avoid defining more than one one-to-one association between any two classes. If you must, leave the associations unidirectional. If you don’t have more than one—if there really is exactly one instance of Address per User—there is an alternative approach to the one we’ve just shown. Instead of defining a foreign key column in the USER table, you can use a primary key association.

 

Using a primary key association

Two tables related by a primary key association share the same primary key values.  The primary key of one table is also a foreign key of the other. The main difficulty with this approach is ensuring that associated instances are assigned the same primary key value when the objects are saved. Before we try to solve this problem, let’s see how we would map the primary key association.

 

For a primary key association, both ends of the association are mapped using the <one-to-one> declaration. This also means that we can no longer map both the billing and home address, only one property. Each row in the USER table has a corresponding row in the ADDRESS table. Two addresses would require an additional table, and this mapping style therefore wouldn’t be adequate. Let’s call this single address property address and map it with the User:

 

<one-to-one name="address"

class="Address"

cascade="save-update"/>

 

Next, here’s the user of Address:

<one-to-one name="user"

class="User"

constrained="true"/>

 

The most interesting thing here is the use of constrained="true". It tells Hibernate that there is a foreign key constraint on the primary key of ADDRESS that refers to the primary key of USER.

 

Now we must ensure that newly saved instances of Address are assigned the same identifier value as their User. We use a special Hibernate identifier-generation strategy called foreign:

 

<class name="Address" table="ADDRESS">

<id name="id" column="ADDRESS_ID">

<generator class="foreign">

<param name="property">user</param>

</generator>

</id>

...

<one-to-one name="user"

class="User"

constrained="true"/>

</class>

 

The <param> named property of the foreign generator allows us to name a one-toone association of the Address class—in this case, the user association. The foreign generator inspects the associated object (the User) and uses its identifier as the identifier of the new Address. Look at the table structure in figure 6.8.  The code to create the object association is unchanged for a primary key association;  it’s the same code we used earlier for the many-to-one mapping style.

image004.gif

 

 

原贴地址: http://www.blogjava.net/asktalk/archive/2005/08/18/10384.aspx

posted on 2006-12-08 10:18 OMG 阅读(1469) 评论(0)  编辑  收藏 所属分类: Hibernate

只有注册用户登录后才能发表评论。


网站导航:
 

<2006年12月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

常用链接

留言簿(1)

随笔分类

随笔档案

IT风云人物

文档

朋友

相册

经典网站

搜索

  •  

最新评论

阅读排行榜

评论排行榜