瀵逛簬榪欑鏂規硶瑕佹敞鎰忓嚑鐐癸細
渚嬪錛屼笅闈㈢殑浠嬬粛涓?/SPAN>use涓殑涓や釜瀛楁鍚屾椂褰卞皠adress錛屽彧鑳藉瀹炵幇鍗曞悜one-to-one,涔熷氨鏄粠use鍒?/SPAN>adress錛屼笉鑳藉瀹炵幇浠?/SPAN>adress鍒?/SPAN>use.鐒朵絾涓嬮潰涔熶粙緇嶄簡鍙互浣跨敤澶嶆潅鐨勬柟娉曟潵瑙e喅錛屼絾鏄緱涓嶅伩澶便?/SPAN>
絎簩縐嶆柟娉曪細鍩轟簬涓婚敭鍏寵仈鐨?/SPAN>one-to-one,榪欑鏂規硶姣旇緝鐩存帴銆備篃灝辨槸璁?/SPAN>adress鐨勪富閿煎拰use鐨勪竴鏍峰氨鍙互浜嗭紝閫氳繃
<id name="id" column="ADDRESS_ID">
<generator class="foreign">
<param name="property">user</param>
</generator>
鏉ユ妸adress鐨勪富閿煎拰use鐨勪富閿肩浉絳夈傚叾浣欑殑璁劇疆閮芥槸灝忎簨銆?/SPAN>
瀵逛簬鍒濆鑰呮潵璇村簲璇ユ敞鎰忥細鍗曞湪use鍜?/SPAN>adress涓緗?/SPAN>one-to-one鏄笉琛岀殑錛岄渶瑕佽緗笂闈㈢殑浠g爜錛岄渶瑕佸疄鐜?SPAN lang=EN-US style="FONT-SIZE: 14pt; mso-font-kerning: 0pt">one-to-one涓ょ鐨勫璞′富閿肩浉鍚岋紝榪欐槸鏈涓昏鐨?/SPAN>銆傝繖涔熸槸one-to-one涓?/SPAN>many-to-one鐨勪笉鍚屼箣澶勩傚簲褰撴敞鎰忋?/SPAN>
fasttalk
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鈥檛 seem to be a good description of either end of a one-to-one association! However, from Hibernate鈥檚 point of view, there isn鈥檛 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鈥檝e 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鈥攔esulting 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鈥攂ut we鈥檝e decided that each Address has just one User, so this can鈥檛 be the right solution. We don鈥檛 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("
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();
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鈥檛 make both the billingAddress and homeAddress associations bidirectional, since we don鈥檛 know if a particular address is a billing address or a home address. (We can鈥檛 decide which property name鈥攂illingAddress or homeAddress鈥攖o 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鈥檚 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鈥檛 have more than one鈥攊f there really is exactly one instance of Address per User鈥攖here is an alternative approach to the one we鈥檝e 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鈥檚 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鈥檛 be adequate. Let鈥檚 call this single address property address and map it with the User:
<one-to-one name="address"
class="Address"
cascade="save-update"/>
Next, here鈥檚 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鈥攊n 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鈥檚 the same code we used earlier for the many-to-one mapping style.