天天看點

One to One 的資料庫模型設計與NHibernate配置

在資料庫模型設計中,最基本的實體關系有三種:一對一、一對多、多對多。關于一對多和多對多使用的情況較多,之前也有過一些讨論,現在來說明一下在資料庫中一對一的模型設計。

首先,關系資料庫中使用外鍵來表示一對多,使用中間表和兩邊的外鍵來表示多對多,而一對一的話有三種表示方式:一種是使用相同的主鍵值,第二種是使用單邊的外鍵,第三種就是使用雙邊外鍵。

1.主鍵關聯

比如我們在做一個er系統時,設計了一個employee表儲存員工的基本資訊(主表),另外有一個employeephoto表(外表),用于儲存員工的證件照,員工和照片之間就是一對一的關系。

下面是fluentnhibernate的mapping配置:

這裡需要注意的是employeephoto的主鍵,不再是普通的生成方式,而是要選擇通過employee做外鍵生成。

關于nhibernate 的one to one标簽上的constrained="true",該标簽在外表上設定,千萬不要在主表上設定。就是說明這個表的主鍵與另一個表的主鍵建立外鍵限制,也就是說在生成sql腳本時,會為這個表建立外鍵,如果不加,是不會建立外鍵的。另外還有一個作用,就是在查詢外表時,如果沒有設定該屬性,那麼就會join主表,而設定了該屬性,就隻需要查詢外表。

在主鍵關聯的情況下,如果從主表中移除從表的引用,這個時候儲存主表,是不會删除從表的,也不會删除這個一對一的關系的。也就是說,我們不能單獨保留employee和photo表,同時還要去掉兩者之間的關系。

2.單向外鍵關聯

比如我們做個中學的管理系統,設計了一個class表儲存班級,另一個classroom表儲存教室,班級和教室是一對一的關系,一個班級有且僅有一個教室,一個教室屬于0到1個班級。

mapping的代碼是:

這裡兩個表中隻需要有一個表持有對方的主鍵作為外鍵即可,我們可以在class表中添加classroom_id來作為外鍵,也可以在classroom表中添加class表作為外鍵。選擇哪一個好呢?如果互相之間都對應的是0到1個對方,那麼其實選哪邊都無所謂,但是如果我們假定一個class必須要對應一個classroom,而一個classroom可以對應0到1個class,那麼我們就必須在class表中添加classroom_id,因為我們必須先建立classroom,然後再建立class,然後可以在資料庫中将class表中的classroom_id設定為不允許為空(當然,設定為允許為空也沒有問題,這樣可以幫助nhibernate在級聯儲存時能夠正确儲存而不報錯)。

單向外鍵關聯時,如果資料庫允許classroom_id為空,那麼是可以打斷class和classroom的關系的,而使得這兩個對象獨立存在,這一點是和主鍵關聯所不一樣的地方。

另外,這個配置還存在一個問題,就是對于一個存在的classroom a,我接下來建立class x,class y,都可以将這些 class的班級指向a,同時這也是儲存成功的。但是這顯然是不對的,我們需要的是一對一,不是一對多。如果查詢classroom a的class屬性,那麼就會報錯,因為根本不知道應該是x還是y。是以我們需要在class表的classroom_id上建立唯一限制,展現在mapping上就是:

這其實又帶來了另外一個問題,這可能是nhibernate沒有考慮到的地方,那就是我們采用的是軟删除,也就是說根本不會從資料庫删除資料,隻是把is_deleted置為1。 那麼,我們如果先儲存了a和x的關系,接下來由于x被取消,是以我删除了x,接下來添加y與a關聯就會失敗。是以需要取消唯一限制,就可以儲存y了,但是在取a的class屬性時仍然會出現異常,取不出正确的class y,這個暫時無解。

3.雙向外鍵關聯

就是說class表中有classroom_id,然後在classroom表中也有class_id。這是非常不推薦的方式,一來導緻資料維護重複,二來導緻資料可能存在不一緻。是以,這裡我就不再累述這種方案的實作了。

示例代碼下載下傳:

<a href="http://files.cnblogs.com/studyzy/one2onetest.7z">http://files.cnblogs.com/studyzy/one2onetest.7z</a>