NHibernate系列之一_主鍵策略

  • 41072
  • 0

摘要:NHibernate系列之一_主鍵策略

由於很早就在學習NHibernate,便一直認為資料庫設計使用替代鍵是種較好的做法。但在職場打滾多年,所遇見的人多半是採用自然鍵。所謂的自然鍵 (Nature Key),就是像身分證字號、名字+出生日等一切可證明資料列為唯一值的資訊。而替代鍵(Surrogate Key),即採用一個無意義不會重複的鍵,來識別資料列。

Martin Fowler在EPOAA中有一篇Identity Field專門在討論主鍵的策略。他說使用自然鍵是有危險的,人為指定自然鍵,是有可能打錯的。當它被很多Table關連時,修正它是很痛苦的。另一個問 題是要用簡單鍵還是複合鍵,當然複合鍵多半是有意義的。Refactoring Database上說,使用複合鍵要小心當欄位屬性發生異動時,更改它也是很痛苦的。所以無論如何,使用一個簡單的替代鍵好處是比較多的。

當然,如果受限於傳統的資料庫設計就是用自然鍵,NH也可以處理這種情形,這叫複合主鍵。假設我有兩個類別,關係如下。

其中Person採用自然複合主鍵策略,Name與Birthday是它的複合主鍵,NH的設定如下


    
      
      
    

    
   
  


必須注意的,就是Person這個類別一定要複寫掉Equals與GetHashCode

   public override bool Equals(object obj)
   {
       if (obj == null)
       {
          return false;
       }

       Person p = obj as Person;
       if(p == null) 
       {
           return false;
       }

       return (p.Name == Name) && (p.Birthday == Birthday);

   }

   public override int GetHashCode()
   {
       return Name.GetHashCode() + Birthday.GetHashCode();
   }

取出這個物件時,可不是靠Id

    //new出空物件,指定其複合主鍵的值
    Person person = new Person();
    person.Name = "Jack";
    person.Birthday = new DateTime(1976, 4, 15);

    person = session.Get(person);

Room有一屬性HouseHolder關連至Person,NH的設定如下

 
    
      
    

    
      
      
    

  



如果想要新增Room

    Room room = new Room();
    Person person = new Person();
    person.Name = "Sherk";
    person.Birthday = new DateTime(1978, 9, 4);
    person.Tel = "2345678";

    room.HouseHolder = person;
    session.Save(room);

可以發現NH很聰明的知道,複合主鍵是不能重複的,所以事先查詢了Person,確認是否有重複的物件。

   NHibernate: SELECT person_.Name, person_.Birthday, person_.Tel as Tel5_ FROM Person person_ 
   NHibernate: INSERT INTO Person (Tel, Name, Birthday) VALUES (@p0, @p1, @p2);@p0 = '2345678' 
   NHibernate: INSERT INTO Room (PersonName, PersonBirthday) VALUES (@p0, @p1); select SCOPE_IDENTITY()