Entity Framework - 一個組織階層的ORM範例(下)
前篇文章介紹了如何架構一個組織階層的設計,並透過EF實現OO的做法.
而最後的查詢確相當不直覺,因為使用端必須了解底層資料結構查詢的方式,這破壞了OO三大原則中的封裝.
底下開始介紹如何封裝這部分.
以往最常看到的方式就是將某些方法直接封裝在Domain物件中.
譬如在Customer物件增加新增刪除的功能
public class Customer
{
public int Id { get; set; }
public string CustomerName { get; set; }
public void AddCustomer(string customerName)
{
...
}
public void DeleteCustomer(int customerId)
{
...
}
}
上述做法常在一些書籍或網站中看到,而這種做法不能說不對,而是不好.因為這破壞了OO設計中的一些準則,物件的責任除了描述物件本身外,還產生與物件無關的行為(Add與Delete),這會產生 高耦合度與低凝聚力 的問題.
所以最好的方式應該將AddCustomer與DeleteCustomer切割出來.
但問題是該放到哪?
如果使用EF有人可能會直接將這些方法放置到實作ObjectContext物件中.如同EF精靈產生的ObjectContext物件包含了很多如Customers,Employees等ObjectQuery物件.
這麼作不能說是不對但也有缺點 1.如果物件很多,相對的ObjectContext物件會有落落長的如AddXXX等函式 2.如果出現與DB無關的一些方法放置在ObjectContext就顯得奇怪,但若另外放置到其他地方又會導致使用端使用時必須了解方法在哪.
而這問題的解決方案有個比較好的做法就是透過 repository pattern(責任樣式),而目前EF4也建議使用repository pattern來處理這類問題.
因repository pattern搭配EF作法每個人想法不同,但最終理念是相同的,所以提供兩篇文章做參考,文中就不詳述(其實是懶得打…)
兩篇文章
http://www.codeproject.com/KB/database/ImplRepositoryPatternEF.aspx
而我本身也有自己的想法做了相關的repository class,與上面不同的是我多了搭配Ioc樣式(參考說明:http://dev.csdn.net/develop/article/24/24397.shtm)為了方便事後的Unit Test.
所以首篇文章的查詢最終在使用端就會封裝為下面程式的使用方式
using (ICustomerRepository repository = ObjectRepositoryFactory.GetRepository<ICustomerRepository>())
{
Customer cus = repository.GetCustomerById(1);
List<Customer> list = repository.CreateQuery().Where(c => c.Parent.Id == 1).ToList();
}
透過repository pattern將相關方法封裝在類別中,使用端就不需了解細節的處理.
當然EF配合repository pattern還有很多細節,下次再介紹了.
這兩篇文章省略掉了很多細節,將焦點聚集在如何透過EF與OO解決一些問題, 並未太深入一些技術上的介紹,未來將會再慢慢補充這些資料,