摘要: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()