二、1—1
無論是單向1-1映射關聯,還是雙休1-1映射關聯,都有三種映射策略:基於主鍵、基於外鍵、采用連接表。
1、單向1-1映射關聯
1.1、基於主鍵的單向1-1映射關聯
對於基於主鍵的單向1-1關聯,基於主鍵關聯的持久化類不能擁有自己的主鍵生成器策略,它的主鍵由關聯實體來負責生成。
是根據他自己的person屬性來獲得的。即他通過自身的一個getPerson()方法來獲得Person對象。然後通過Person對象中的getID()方法獲得id,然後賦值給自身id。這樣就可以不需要自己來生成id。
采用基於主鍵的1-1關聯時,應使用<one-to-one…/>元素來映射關聯實體,配置<one-to-one…/>元素時需要指定一個name屬性。
實例(Person<–IDCard)
Person
[java]
public class Person {
private Integer id;
private String name;
private IDCard idCard;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IDCard getIdCard() {
return idCard;
}
public void setIdCard(IDCard idCard) {
this.idCard = idCard;
}
}
IDCard:
[java]
public class IDCard {
private Integer id;
private String useLife;
public String getUseLife() {
return useLife;
}
public void setUseLife(String useLife) {
this.useLife = useLife;
}
private Person person;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
映射文件:
Person.hbm.xml
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="Person" table="person">
<id name="id" column="personID">
<generator class="native" />
</id>
<property name="name" column="personName" />
</class>
</hibernate-mapping>
IDCard.hbm.xml
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="IDCard" table="idCard">
<id name="id" column="idCardID">
<!– 基於主鍵關聯時,主鍵生成策略是foreign,表明根據關聯類的主鍵來生成該實體的主鍵 –>
<generator class="foreign">
<!– 指定引用關聯實體的屬性名 –>
<param name="property">person</param>
</generator>
</id>
<property name="useLife" column="useLife" />
<one-to-one name="person" constrained="true" />
</class>
</hibernate-mapping>
在上面的映射文件中,采用這種關聯映射策略是,idCard表作為從表,此時idCard表的主鍵將沒有自己的主鍵生成策略。他是根據person表中的主鍵來生成的。同時從表(idCard)裡記錄的主鍵將會與主表(person)裡的記錄保存一致。
IDCard中的id既是主鍵也是外鍵。那麼idCard表如何通過person表來生成主鍵的呢?
foreign生成器中有一個元素:property。這個元素代表瞭該表的外鍵是從哪一個屬性中獲得的。通過上面的配置可以發現idCard表的外鍵是從person屬性中獲得的。它的外鍵就是通過person屬性中的getId獲得id,然後將該id直接賦給id。
使用constrained="true"表明該類對應表和被關聯的對象所對應的數據庫表之間通過一個外鍵引用對主鍵進行約束。
通過上面的配置後,就可以對兩個實體進行操作瞭:
[java]
static void add(){
Session session = null;
Transaction tx = null;
try{
session = HibernateUtil.getSession();
tx = session.beginTransaction();
IDCard idCard = new IDCard();
idCard.setUseLife("10年");
Person person = new Person();
person.setName("chentmt");
idCard.setPerson(person);
session.save(person);
session.save(idCard);
tx.commit();
}finally{
if(session!=null)
session.close();
}
}
1.2、基於外鍵的單向1-1映射關聯
基於外鍵的關聯映射與一般的N-1關聯映射沒有多大區別,隻需要將<many-to-one…/>元素中增加unique="true"屬性即可。如下:
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="IDCard" table="idCard">
<id name="id" column="idCardID">
<generator class="native" />
</id>
<property name="useLife" column="useLife" />
<many-to-one name="person" column="personID" unique="true"<span style="color:#ff6666;"> </span>/>
</class>
</hibernate-mapping>
unique="true"代表瞭idCard表的personid外鍵列上增加瞭唯一約束–這樣就完成基於外鍵的單向1-1映射瞭。
其他的配置文件和持久化類都不需要做修改。
1.3、有連接表的單向1-1映射關聯
和上面差不多,隻需要在有連接表的N-1關聯映射中的<many-to-one…/>元素增加一個unique="true"即可。如下:
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="IDCard" table="idCard">
<id name="id" column="idCardID">
<generator class="native" />
</id>
<property name="useLife" column="useLife" />
<!– 使用join元素強制使用連接表 –>
<join table="person_idCard">
<key column="idCardID"/>
<many-to-one name="person" column="personID" unique="true"/>
</join>
</class>
</hibernate-mapping>
2、雙向1-1關聯映射
對於雙向的1-1關聯需要讓兩個持久化列都增加引用關聯實體的屬性,並為該屬性提供setter和getter方法。持久化類:如上。
2.1基於主鍵的雙向1-1關聯映射
基於主鍵的雙向1-1關聯映射同樣需要在一端的主鍵生成器策略使用foreign策略,表明將根據對方的主鍵來生成自己的主鍵,本實體不能擁有自己的主鍵生成策略。另一端需要使用<one-to-one…/>元素用來映射關聯實體,否則就變成瞭單向的。映射文件如下:
Person.hbm.xml
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="Person" table="person">
<id name="id" column="personID">
<generator class="native" />
</id>
<property name="name" column="personName" />
<!– 映射關聯實體 –>
<one-to-one name="idCard" />
</class>
</hibernate-mapping>
IDCard.hbm.xml
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="IDCard" table="idCard">
<id name="id" column="idCardID">
<!– 基於主鍵關聯時,主鍵生成策略是foreign,表明根據關聯類的主鍵來生成該實體的主鍵 –>
<generator class="foreign">
<!– 指定引用關聯實體的屬性名 –>
<param name="property">person</param>
</generator>
</id>
<property name="useLife" column="useLife" />
<one-to-one name="person" constrained="true" />
</class>
</hibernate-mapping>
對於操作這個兩個實體增加同時。因為可以通過兩邊來訪問,所以這裡就演示查詢
這裡查詢分為兩種:基於主表查詢和基於從表查詢
基於主表查詢(通過主表查詢從表記錄)
[java]
static void query(int personid){
Session session = null;
try{
session = HibernateUtil.getSession();
Person person = (Person) session.get(Person.class, personid);
System.out.println("useLife="+person.getIdCard().getUseLife());
}finally{
if(session!=null)
session.close();
}
}
我們知道對於N-1關聯查詢的時候,系統會產生兩條sql查詢語句來檢索從表對象:一條先查詢主表,然後根據外鍵從從表中獲取相對應的記錄。但是對於1-1關聯時,它並不是產生兩條sql語句來查詢。而是一條sql語句,通過外連接來連接兩張表的。如下
[sql]
Hibernate: select person0_.personID as personID1_1_, person0_.personName as personName1_1_, idcard1_.idCardID as idCardID2_0_, idcard1_.useLife as useLife2_0_ from person person0_ left outer join idCard idcard1_ on person0_.personID=idcard1_.idCardID where person0_.personID=?
基於從表查詢(通過從表查詢主表)
[java]
static void query(int personid){
Session session = null;
try{
session = HibernateUtil.getSession();
IDCard idCard = (IDCard) session.get(IDCard.class, 1);
System.out.println(idCard.getPerson().getName());
}finally{
if(session!=null)
session.close();
}
}
通過從表查詢主表與通過主表查詢從表又有點不同瞭。在這裡它不再是產生一條sql語句,而是兩條。如下:
[sql]
Hibernate: select idcard0_.idCardID as idCardID2_0_, idcard0_.useLife as useLife2_0_ from idCard idcard0_ where idcard0_.idCardID=?
Hibernate: select person0_.personID as personID1_1_, person0_.personName as personName1_1_, idcard1_.idCardID as idCardID2_0_, idcard1_.useLife as useLife2_0_ from person person0_ left outer join idCard idcard1_ on person0_.personID=idcard1_.idCardID where person0_.personID=?
它會先查詢從表,獲取記錄,然後再通過外連接方式連接兩張表根據personID獲取記錄。
2.2基於外鍵的雙向1-1關聯映射
對於基於外鍵的雙向1-1關聯映射。外鍵可以存放任意一邊。需要存放外鍵的一端,需要增加<many-to-one../>元素。同時也需要添加unique="true"屬性。
對於雙向單位1-1關聯映射,兩個實體原本是處於平等狀態的。但是當我們選擇一個表來增加外鍵後,該表就變成瞭從表,另一個表變成主表。
另一端需要使用<one-to-one../>元素,該元素需要使用name屬性指定關聯屬性名,同時也需要使用property-ref屬性來指定引用關聯類的屬性。property-ref的值是從表中的引用屬性。
映射文件如下:
Person.hbm.xml
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="Person" table="person">
<id name="id" column="personID">
<generator class="native" />
</id>
<property name="name" column="personName" />
<!– 映射關聯實體 –>
<one-to-one name="idCard" property-ref="person"/>
</class>
</hibernate-mapping>
IDCard.hbm.xml
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="IDCard" table="idCard">
<id name="id" column="idCardID">
<generator class="native" />
</id>
<property name="useLife" column="useLife" />
<many-to-one name="person" column="personID" unique="true" />
</class>
</hibernate-mapping>
2.3有連接表的雙向1-1關聯映射
采用這個方式是非常少的,因為這中情況映射相當復雜,數據模型繁瑣,一般不推薦采用這種策略。
雙向1-1關聯兩端都需要使用<join…/>元素指定連接表,<join../>元素的table屬性用於指定連接表的表名,所有兩端的table屬性值應該是一致的。同時兩個也需要增加key元素映射連接表的外鍵列,還需要增加<many-to-one../.>元素映射關聯屬性,兩個<many-to-one…/>元素都需要增加unique="true"屬性。註意這裡兩端的key元素和<many-to-one../>中column的屬性值應該是相反的。
同時為瞭讓hibernate在連接表的兩個數據列上增加唯一約束,映射文件應該為兩個<key…/>元素指定unique="true"。
當使用連接表來建立1-1關聯關系時,兩個實體應該是絕對的平等,不存在任何的主從約束關系,hibernate映射他們的連接表時,將會選擇某一個外鍵作為連接表的主鍵–因此兩個持久化類的映射文件依然不是完全相同的。映射文件必須在一端的<join…/>元素中指定inverse="true",而另一端則指定option="true"。下面是兩個映射文件
Person.hbm.xml
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="Person" table="person">
<id name="id" column="personID">
<generator class="native" />
</id>
<property name="name" column="personName" />
<join table="person_idCard" inverse="true">
<key column="personID" unique="true" />
<many-to-one name="idCard" column="idCardID" unique="true" />
</join>
</class>
</hibernate-mapping>
IDCard.hbm.xml
[html]
<hibernate-mapping package="com.hibernate.domain">
<class name="IDCard" table="idCard">
<id name="id" column="idCardID">
<generator class="native" />
</id>
<property name="useLife" column="useLife" />
<join table="person_idCard" optional="true">
<key column="idCardID" unique="true" />
<many-to-one name="person" column="personID" unique="true"></many-to-one>
</join>
</class>
</hibernate-mapping>
作者:chenssy