體驗ADO.NET Entity Framework的繼承

ADO.NET Entity Framework(以下簡稱ADO.NET EF)有一個非常可信的運行時。之所以不敢在項目中廣泛使用是因爲其糟糕的設計時。這個DSL設計時糟糕在哪裏呢?其一,只能是先設計好數據庫後設計實體模型;其二,如果你修改了數據庫結構,再更新實體模型時,你所做的修改全部作廢,最糟糕的是,很可能會出現映射錯誤,你必須手工來維護EDMX中的MSL部分。通常數據庫結構的修改會成爲你的噩夢。
還必須指出一點,ADO.NET EF在MSDN中的文檔是有問題的。不信你看我的發現:MSDN,微軟怎麼會這樣啊?
不得不承認,ADO.NET EF的運行時對繼承關係的處理是非常讓人舒服的。本文帶你去體驗一下ADO.NET EF的繼承。
與通常的繼承關係映射一樣,支持三種方式:
  • 一體系一表方式
  • 一類一表方式
  • 一具體類一表方式
對於第一種方式和第三種方式,我是非常不屑的。我有文章講過我的看法:細說繼承關係映射
第一種方式有一篇文章已經講了具體的操作方式:Single Table Inheritance in Entity Framework。這種方式有什麼問題呢?那個“Type”字段我們是可以接受的,因爲在運行時這個字段完全是透明的;但是那個“Salary”、“Rate”和“Hours”可以爲空,這個我們不能接受,因爲這意味着例如我們存貯一個SalariedExployee實體,可以堂而皇之地不給Salary賦值,而導致業務錯誤。這便是我所反感的“可空冗餘”。不過凡事都有例外,如果派生類中的屬性剛好都是可空的,那這個可空就不冗餘了,而單表繼承簡單高效的好處就可以坐收了。
第三種方式我是無法接受的,因爲根本解決不了我多次提到的“關係共享”的問題。
還好,ADO.NET EF提供了完美的第二種方式支持。有文章講這個方式:
不過,我沒有按這篇文章所提示的方式設置成功,也許我的環境不同。重要的是,我明白了設置繼承的幾個要點:第一,不要手工修改BaseType來設置繼承,而是要用上下文菜單中的“添加”→“繼承”的方式。我們於是相信,除了BaseType以外,ADO.NET EF的DSL爲EDMX中的MSL部分加入了某些內容。第二,手工刪除派生類中的關鍵字段屬性。第三,注意操作順序。
現在用一個實例來說明。這個例子用於解決關於權限的問題。業務系統對權限的判斷僅根據其是否擁有某個“權柄”。這個權柄用一個字符串表示在Privilege表中。這個權柄只可以授予給角色。用戶和用戶組都可以隸屬於某個角色,用戶組中的用戶可以從該用戶組繼承所有的角色。實際上的應用可能會在權柄上再做一些文章,例如加上權柄作用域對象。這與本主題沒有關係,就此省略。
下圖是數據庫的設計:
在VS2008中建立一個類庫項目。新增一個名叫“InheritanceDemoModel.edmx”的實體數據模型,並從建立好的數據庫生成,把實體連接設置命名爲“DemoEntities”。於是,得到這個最初的成果:
先刪除UserOrGroup和User之間的關係,再刪除UserOrGroup與Group之間的關係,然後把所有的實體集名稱改成複數。
現在加入兩個繼承關係:一個是UserOrGroup爲基,Group爲派生;另一個是UserOrGroup爲基,User爲派生。然後,變成這樣:
下一步,先把UserOrGroup的“抽象”屬性改爲“true”,再刪除User的UserId屬性和Group的GroupId屬性。刪除這兩個屬性以後,要分別把原來的兩個字段(Column)映射到UserOrGroup的Id字段:
最後一步,由於刪除了User的UserId屬性和Group的GroupId屬性,Group的Users屬性和User的Groups屬性映射被破壞了,需要重新映射。
保存,完成映射。接下來可以做幾個測試,例如,測試分別創建幾個Privilege、Role、Group、User,然後用一個簡單的Linq表達式來獲取某個User所有的權柄。
代碼就不貼了,有興趣下載代碼吧。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章