hibernate(五) hibernate一對一關係映射詳解

    序言

        之前講解了一對多(單向、雙向)、多對多(雙向),今天就講解一下最後一個關係,一對一。 心情不錯。狀態也挺好的,趕緊寫一篇博文造福一下大家把。  

                                                  --WH

 

 一、一對一關係的概述

      一對一關係看起來簡單,其實也挺複雜的。其中關係就包含了四種,單向雙向和主鍵關聯外鍵關聯。 什麼意思呢,也就是包含了單向一對一主鍵關聯、雙向一對一主鍵關聯,單向一對一外鍵關聯,雙向一對一外鍵關聯, 這四種中,單雙向就不用在說了把,就是看你業務需求來去設置是否是單雙向,而外鍵關聯也很簡單,前面的一對多和多對多度是依靠外鍵關聯關係來寫的。那主鍵關聯關係是怎麼樣的呢?其實跟外鍵關聯差不多,唯一的區別就是,讓一個類的主鍵當作外鍵使用來指向另一個關聯類的主鍵,從而兩個類的主鍵就達到了同步,也就是一致。你的主鍵是什麼我的主鍵就是什麼。如果這看不懂,那麼就看下面的詳細講解的。

 

 

二、單向一對一主鍵關聯

      通過人和身份證這個一對一的例子來解釋。

          實體類的屬性

                 

          數據庫關係圖

              person中的id既是主鍵又是指向IdCard主鍵的外鍵。通過外鍵得特性,可以知道person的id和IdCard的主鍵id要相同,所以這才叫做主鍵關係。

                   

    IdCard.java和IdCard.hbm.xml

 

複製代碼

public class IdCard {
    private int id;
    private String cardNo;
  //。。。  
}

//IdCard.hbm.xml
//這個沒什麼好說的,因爲是單向一對一,這個就正常寫,他不用幹什麼。
<class name="domain1.IdCard" table="idcard">
        <id name="id" column="id">
            <!-- 主鍵生成策略 使用native,需要底層數據庫自己設置主鍵的值哦,比如AUTO_INCREMENT -->
            <generator class="native">
            </generator>        
        </id>
        <!-- 一些常規屬性 -->
        <property name="cardNo"></property>

複製代碼

 

    Person.java和Person.hbm.xml

複製代碼

public class Person {
    private int id;
    private String name;
    private IdCard idCard;//體現一對一的關係。保存映射類的實例對象。
//。。。
}

//Person.hbm.xml
<hibernate-mapping>
    <class name="domain1.Person" table="person">
        <id name="id" column="id">
            <!-- 重點在這裏。主鍵生成策略 因爲主鍵跟外鍵是同一個,所以直接在這裏申明該主鍵就是外鍵,並且指向了idCard這個類 -->
            <generator class="foreign">
            <param name="property">idCard</param>
            </generator>        
        </id>
        <!-- 一些常規屬性 -->
        <property name="name"></property>
        <!--由於在申明主鍵的時候已經將關係寫清楚了,所以在這裏沒有column這個屬性。按平常的習慣,我們會在這裏寫上column="數據庫中外鍵字段屬性名稱。"-->
    <!--constrained屬性:就是表明我們的主鍵當外鍵使用了。 這個屬性兩個作用,一是通知這種對應關係在上面已經寫過了,所以這裏纔不需要寫column,二是表明這種關係是什麼,也就是主鍵當外鍵。
      其實還有一個級聯關係的作用,這裏不做多說明,具體會在這章之後一起講解,不然會讓人感覺很混亂。-->
        <one-to-one name="idCard" constrained="true"></one-to-one>

    </class>   

複製代碼

 

    添加測試數據

複製代碼

        //省略前面獲得session的步驟和後面關閉session事物提交的步驟,只看關鍵代碼,這裏先添加一條測試數據
        
        IdCard idCard = new IdCard();
        idCard.setCardNo("11111111");
        
        Person person = new Person();
        person.setName("qqq");
        
        person.setIdCard(idCard);
        
        session.save(idCard);//這個其實可以不用的,講了級聯就可以省略的,現在先保留下來,大神的話看看不說話就好哦
        session.save(person);
        

        

複製代碼

    

    現在來真正測試一下這個單向一對一主鍵關係

    

複製代碼

    //這樣會報異常,因爲我們設置的是單向一對一,從person到Idcard,所以從idcard是查不到person。java.lang.NullPointerException
            IdCard idCard = (IdCard)session.get(IdCard.class, 1);
        
        System.out.println(idCard.getPerson().getName());;

        //但是這樣就查得到一個人的idCard
                Person person = (Person)session.get(Person.class,1);
                person.getIdCard().getCardNo();

複製代碼

      到這裏,單向一對一主鍵關聯就講解完了,知道了單向,雙向就so easy了,

二、雙向一對一主鍵關聯

            實體類屬性

                這個圖中雙向箭頭的意思是不管從那邊查找,度能夠找到對方,比如,person到Idcard:直接拿自己的主鍵值到對方表中查找主鍵值一樣的,查找到了就將該記錄放到自己的idCard屬性中,就行了  idCard到person也是一樣,拿主鍵值到對方表中查找主鍵值相同的。查找到了就將記錄放到person屬性變量中。

            

            數據庫關係

              

        

 

跟單向一對一主鍵關係基本上一樣,只需要在IdCard這個實體類上加上一個Person person來保存對應的person實例對象,並且在IdCard.hbm.xml中加上一個<one-to-one>的映射關係,來看一下

      其他度不變,我寫出來的就是要變化的

      IdCard.java和IdCard.hbm.xml

複製代碼

public class IdCard {
    private int id;
    private String cardNo;
    private Person person;//多了這個
//...
}
IdCard.hbm.xml
    <class name="domain1.IdCard" table="idcard">
        <id name="id" column="id">
            <!-- 主鍵生成策略 -->
            <generator class="native">
            </generator>        
        </id>
        <!-- 一些常規屬性 -->
        <property name="cardNo"></property>
        <!-- 這裏只需要寫這些就足夠了,因爲one-to-one默認使用的就是用主鍵跟關聯類的主鍵進行比較,本來就是主鍵關係,通過主鍵跟主鍵比較,就能達到目的,所以這個中沒有column這個屬性,
      
     但是可以配置一些別的屬性,不需要寫column, -->
        <one-to-one name="person"></one-to-one>

複製代碼

 

    測試

  現在在通過Idcard查找person就不會報異常了,可以找到。

複製代碼

        
        
        IdCard idCard = (IdCard)session.get(IdCard.class, 1);
        
        System.out.println(idCard.getPerson().getName());;
//運行發送的sql語句和結果
Hibernate: 
    select
        idcard0_.id as id3_1_,
        idcard0_.cardNo as cardNo3_1_,
        person1_.id as id4_0_,
        person1_.name as name4_0_ 
    from
        idcard idcard0_ 
    left outer join
        person person1_ 
            on idcard0_.id=person1_.id 
    where
        idcard0_.id=?
qqq

複製代碼

 

    注意:主鍵關係的一對一的缺點:不知道你們發現了沒有,在增加實驗數據的時候,必須得先有Idcard,纔能有person,

 

三、單向一對一外鍵關聯

    理解了主鍵關聯,這個外鍵關係非常簡單,因爲他就是多對一的一個特例,如果多端控制爲1個的話,那不就是一對一了嗎,這裏要注意站的角度問題,多對一重點在多端,如果是一對多的話,重點在一端,一端本來就是1了,就沒有所謂的特例了,所以還是要到多端去設置讓他唯一,這樣就打到了一對一關係,因此上面說的是多對一的一個特例,這樣解釋應該清楚了。如何設置多端唯一呢,通過一個屬性 unique=ture。

    來看看數據庫關係圖(跟一對多的數據庫關係模型一樣)

            

    實體類中屬性

          因爲是單向一對一,從Person到IdCard,所以Person中多一個能存放IdCard實例對象的屬性

          

 

  IdCard.java和IdCard.hbm.xml

複製代碼

public class IdCard {
    private int id;
    private String cardNo;
//。。。
}
IdCard.hbm.xml
//很普通的一個映射文件
    <class name="domain1.IdCard" table="idcard">
        <id name="id" column="id">
            <!-- 主鍵生成策略 -->
            <generator class="native">
            </generator>        
        </id>
        <!-- 一些常規屬性 -->
        <property name="cardNo"></property>
        </class>

複製代碼

 

  Person.java和Person.hbm.xml

複製代碼

public class Person {
    private int id;
    private String name;
    private IdCard idCard;
//...
}
//Person.hbm.xml
        <class name="domain1.Person" table="person">
        <id name="id" column="id">
            <!-- 主鍵生成策略 -->
            <generator class="native">
            </generator>        
        </id>
        <!-- 一些常規屬性 -->
        <property name="name"></property>
    <!--跟多對一一樣,只是增加了一個unique屬性。這樣就指定了這端爲一了。-->
        <many-to-one name="idCard" column="cardId" unique=true></many-to-one>

    </class>   

複製代碼

 

  增加測試數據

複製代碼

        IdCard idCard = new IdCard();
        idCard.setCardNo("11111111");
        
        Person person = new Person();
        person.setName("qqq");
        
        person.setIdCard(idCard);
        
        session.save(idCard);
        session.save(person);

複製代碼

  測試數據爲,看到這個圖就應該知道我們這裏是用外鍵關係了,在person表中有一個外鍵字段值。

        

  

    真正的測試一下單向一對一,其實也就是從person能查到idcard,但是從idcard查不到person 

複製代碼

    //這樣會報異常,因爲我們設置的是單向一對一,從person到Idcard,所以從idcard是查不到person。java.lang.NullPointerException
            IdCard idCard = (IdCard)session.get(IdCard.class, 1);
        
        System.out.println(idCard.getPerson().getName());;

        //但是這樣就查得到一個人的idCard
                Person person = (Person)session.get(Person.class,1);
                person.getIdCard().getCardNo();

複製代碼

 

 

四、雙向一對一外鍵關係

        雙向也很簡單,只要改變兩個地方,就在IdCard.java和IdCard.hbm.xml中加入這種映射關係就足夠了。

      實體類圖

                

      數據庫關係圖還是跟單向一對一外鍵關係一樣

                  

    IdCard.java和IdCard.hbm.xml

複製代碼

public class IdCard {
    private int id;
    private String cardNo;
    private Person person;//用來存放person對象,一對一關係
//...
}

//IdCard.hbm.xml
    <class name="domain1.IdCard" table="idcard">
        <id name="id" column="id">
            <!-- 主鍵生成策略 -->
            <generator class="increment">
            </generator>        
        </id>
        <!-- 一些常規屬性 -->
        <property name="cardNo"></property>
        <!-- 要注意property-ref這個屬性,很重要,關鍵的地方就在這裏。
        property-ref:指定關聯類的屬性名,這個屬性將會和本類的主鍵相對應。如果沒有指定,
        會使用對方關聯類的主鍵來跟本類的主鍵比較,這裏要注意不是關聯表中的外鍵字段名。如果不指定這個屬性,那麼
        一對一默認會使用主鍵去做對比。相當於原本我們
        是可以通過本類的主鍵去和關聯類的外鍵比較,然後來找到對應記錄的,但是這裏一對一中沒有
        column屬性,所以該方法行不通,因此就想出了這種辦法,不跟外鍵比,也不能跟主鍵比(因爲不是主鍵關係),那麼
        就跟關聯表中的一個屬性比,也就是我們這個person中的idCard屬性,爲什麼找得到呢,因爲從person能找到idcard,那麼
        person中的idCard中就會有對應的值,我們跟該值比,也就能找到對應的person了。
        class:person所在的類,這個也可以不寫,hibernate會自動幫我們找到
         -->
        <one-to-one name="person" property-ref="idCard" class="domain1.Person"></one-to-one>
</class>

複製代碼

 

    測試

      這樣從IdCard就能找到person了。而不是報空指針異常

複製代碼

        
        
        IdCard idCard = (IdCard)session.get(IdCard.class, 1);
        
        System.out.println(idCard.getPerson().getName());;
//運行發送的sql語句和結果
Hibernate: 
    select
        idcard0_.id as id3_1_,
        idcard0_.cardNo as cardNo3_1_,
        person1_.id as id4_0_,
        person1_.name as name4_0_ 
    from
        idcard idcard0_ 
    left outer join
        person person1_ 
            on idcard0_.id=person1_.id 
    where
        idcard0_.id=?
qqq

複製代碼

 

 

 

五、總結

      學完之後,我們應該知道

        1、單向一對一主鍵關聯、雙向一對一主鍵關聯、單向一對一外鍵關聯、雙向一對一外鍵關聯的配置

        2、主鍵關聯的特點:一個表中的主鍵就是外鍵,指向另一個表中的主鍵,所以兩張表的主鍵是相同的,但是有一個缺點,就是必須依賴另一張表的主鍵,這在有些業務邏輯上是行不通的

        3、知道了單向一對一主鍵關聯,那麼雙向一對一主鍵關聯就非常的簡單,其重點在主鍵id中的主鍵生成策略那塊還有constrained屬性的使用

        4、單向一對一外鍵關聯其實就是多對一的一個特例,其中關鍵的地方在unique這個屬性上面

        5、單向一對一外鍵關聯知道後,雙向一對一外鍵關聯也非常簡單,關鍵的地方就在<one-to-one>中property-ref的配置,注意這個的意思是配置關聯類中的屬性,而不是關聯類中的外鍵字段名。

        6、one-to-one默認是使用主鍵和主鍵進行比較來查詢數據,所以其中並沒有column這個屬性。因爲沒有這個column屬性,所以就外鍵關聯中就需要用到第5點的property-ref的屬性了。

轉載於:https://www.cnblogs.com/whgk/p/6128395.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章