在我們基於Domain驅動模式開發面向對象的多層架構的時候,層和層之間數據的傳輸對象(DTO)往往 簡化為領域對象模型,在上文中就是我們利用LINQ TO SQL對象設計器生成的Bill,Customer等實體類。
存在的問題
通常的做法,我們把這些實體類單獨分成一層,這樣程序分層劃分成如下:
數據訪問層(Data Access Layer)
業務層 (Business Layer)
用戶界面層(UI Layer)
實體層(Entity Layer)
注意,多層應用程序,一般遵守這樣的規則:UI調用BL,BL調用DL,不能跨級調用,也不能底層調用 上層,但是實體層是我們的DTO,各個層都可以調用它。
如果這樣劃分,我們系統就出現問題:
我們把RepositoryBase劃到數據層,LINQ TO SQL對象設計器生成的類分到實體層,數據層引用實體層 ,沒有問題,但是我們看到,在我們實體層,存在一個方法(以Bill為例):
public static RepositoryBase<Bill, LINQtoSQLHelper.DataContextSetUp> CreateRepository() { return new BillRepository(); }
數據層也必須引用數據訪問層,循環引用。另外,對於如何體現loadoption那?
解決循環引用
以Bill實體為例,循環引用的病因在於Bill實體中添加這樣一個方法:
public static RepositoryBase<Bill, LINQtoSQLHelper.DataContextSetUp> CreateRepository() { return new BillRepository(); }
為什麼要添加這個方法那?這樣做就是充血模式的實體了。注意到RepositoryBase.cs有一段代碼:
try
{
object Repository = association.OtherType.Type.GetMethod("CreateRepository").Invoke (null, null);
Repository.GetType().GetMethod("IterateEntitySet",
BindingFlags.NonPublic | BindingFlags.Instance).Invoke(
Repository,
new object[4]
{
AssociationProperty.GetValue(theEntity, null),
context,
OperationMode,
Recursively
}
);
}
catch (System.Reflection.TargetInvocationException e)
{
throw (e.InnerException);
}
作者添加這段代碼,主要是利用反射獲取當前實體的CreateRepository方法,實現對象的CRUD操作。 如果實體中去掉這個CreateRepository方法,那這段代碼如何變通,請看:
dd
try
{
object Repository = association.OtherType.Type.GetMethod("CreateRepository").Invoke(null, null);
Repository.GetType().GetMethod ("IterateEntitySet",
BindingFlags.NonPublic | BindingFlags.Instance).Invoke(
Repository,
new object[4]
{
AssociationProperty.GetValue(theEntity, null),
context,
OperationMode,
Recursively
}
);
}
catch (System.Reflection.TargetInvocationException e)
{
throw (e.InnerException);
}
主要利用反射,從當前數據訪問層Assembly中獲得對應實體類的的Repository類。
好,解決循環引用問題。
體現loadoption
這個問題比較棘手,確實在底層無法感知業務需求的東西,而其DataContext是共用的。
能不能另辟捷徑那?注意我們用泛型構造RepositoryBase類,那能不能從中得到什麼那?
我們對類RepositoryBase添加入如下方法:
public IList<TEntityType> Where(string predicate, params object[] values)
{
InitDataContext ();
return m_context.GetTable<TEntityType>().Where (predicate, values).ToList<TEntityType>();
}
public IList<TEntityType> OrderBy(string ordering, params object[] values)
{
InitDataContext();
return m_context.GetTable<TEntityType>().OrderBy(ordering, values).ToList<TEntityType>();
}
public IList<TEntityType> Take(int count)
{
InitDataContext();
return m_context.GetTable<TEntityType>().Take<TEntityType> (count).ToList<TEntityType>();
}
public IQueryable Select(string selector, params object[] values)
{
InitDataContext();
return m_context.GetTable<TEntityType>().Select(selector, values);
}
#endregion
#region Query Methods (Lambda Expression)
public IList<TEntityType> Where(Func<TEntityType, bool> predicate)
{
InitDataContext ();
return m_context.GetTable<TEntityType>().Where (predicate).ToList<TEntityType>();
}
好,這個基本上體現loadoption。
反饋!
本文是對我翻譯上一篇文章的一個補從,代碼你可以自由使用,但是必須聲明出處。
本文配套源碼:http://www.bianceng.net/dotnet/201212/726.htm