.NET 業務架構開發實戰之八 業務層Mapping的選擇策略
前言:在上一篇文章中提到了mapping,感覺很像在重新實現NHibernate。其實文章的本意是想反映出Richard在思考的時候的一些選擇:利用現有的,還是最後自己用別的方式實現。如果一上來就說什麼什麼好,那太武斷了,也很片面,系列文章反覆的在強調一點:技術有它的適用情境,沒有完美的技術。很多的朋友說本系列在近似的開發一個ORM,其實不是:ORM就是把資料庫錶轉為資料實體,但是本篇中是使用已經轉換後的資料實體。是把資料實體的資料給業務類。
而且本篇討論業務類中的mapping,也就是資料的擷取方式,當然,業務類的設計遠遠不止這些。
開始之前希望在這下面的兩點上達到共識:
1. 最好不要把DAL的資料實體(Linq或者Entity Framework產生的),或者原生的DataTable暴露給UI那邊(除非一定要,或者有特殊的原因)。
2. UI使用的是BLL類(或者基於訊息的Scheme格式)。
今天的議題如下:
1.第二種Mapping方法。
2.第三種Mapping方法。
系列文章連結:
[原創].NET 分布式架構開發實戰之一 故事起源
[原創].NET 分布式架構開發實戰之二 草稿設計
[原創].NET 分布式架構開發實戰之三 資料訪問深入一點的思考
[原創].NET 分布式架構開發實戰之四 構建從理想和實現之間的橋樑(前篇)
[原創].NET 分布式架構開發實戰五 Framework改進篇
[原創].NET 業務架構開發實戰之六 DAL的重構
[原創].NET 業務架構開發實戰之七 業務層初步構想
[原創].NET 業務架構開發實戰之八 業務層Mapping的選擇策略
[原創].NET 業務架構開發實戰之九 Mapping屬性原理和驗證規則的實現策略
[原創].NET 業務架構開發實戰之十 第一階段總結,深入淺出,水到渠成(前篇)
[原創].NET 業務架構開發實戰之十 第一階段總結,深入淺出,水到渠成(後篇)
1. 第二種Mapping方法。
Richard思考了設定檔的方式,誠然用設定檔確實靈活,但是靈活也是有代價的,因為Framework最後還得公司的開發人員使用,過多的配置和過高的學習成本使得Framework失去了很大的意義。
Richard開始思考了,想到了還有一種最簡單的mapping的方式:就是直接一個個的賦值,如:
代碼
public class ProductBL
{
public string ProductName { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
public void Mapping(m_Product productEntity)
{
this.ProductName = productEntity.Name;
this.Price = productEntity.Price;
this.Description = productEntity.Description;
}
}
很明顯,這個過程很簡單卻很繁瑣。
和之前使用設定檔的方式相比:
優點:1. 便於使用和理解
2. 便於調試
缺點:1. 和資料實體耦合的很緊(其實這不算是缺點,這是和之前設定檔的方式比較而言認為缺點)。上面的代碼中就直接使用了m_Product.(大家可以參看之前一篇文章中用設定檔的優缺點)
2. 編寫的過程很繁瑣。全部是手動的mapping。
而且還有關鍵的一點就是:查詢對象怎麼產生最終的SQL語句?
例如,下面的代碼:
ICriteria condition=CriteriaFactory.Create(typeof(ProductBL).Where("ProductName", Operation.Equal,"book");
如果採用設定檔的mapping方式,很清楚:在設定檔中ProductBL的ProductName對應m_Product實體的Name欄位,也就是對應資料庫表m_Product的Name欄位(因為在BLL中使用的是通過linq或者Entity Framework產生的m_Product實體)。上面的查詢對象最後產生類似select * from m_Product where Name=’book’的語句。
Richard想到NHibernate的實現:在NHibernate也有查詢對象,在NHibernate中的查詢對象的實現也是依賴NHibernate的那個mapping的設定檔的。
並不是說沒有查詢對象就不行,不用查詢對象,用Linq和Entity Framework也是可以實現的。但是資料層就沒有“以不變應萬變”了的效果,而且開發人員要掌握各種的資料訪問技術:ADO.NET, Linq等。(可以參看.NET 分布式架構開發實戰之三 資料訪問深入一點的思考一文)。
現在Richard面臨的問題就是:
1. 不用設定檔mapping,這樣查詢對象就不好實現。
2. 手動的敲入代碼mapping,重複的勞動。
Richard思考是否更好的方式解決上面的問題。於是第三種方式就產生了。
3. 第三種Mapping方法。
第三種mapping的方法就是綜合了之前兩種mapping的優點,而避開了他們的缺點。
Richard想到解決手動mapping的方法就是:圖形化的代碼產生來代替手寫代碼。而且要想辦法儲存資料庫欄位的一些資訊。
很巧的就是:linq和EF產生的實體中的欄位資訊就反映了資料表欄位的資訊。這點可以利用起來。下面的草圖是用Visio畫出的,代表了Richard的想法。其實Richard也沒有一下就開發出下面的工具,一切還是處於設計階段。
Richard設計出了自動產生代碼的工具(工具的開發Richard思考過了,可以採用最簡單的實現方式:一個Windows程式。也想過用DSL工具開發,但是DSL得學習過程還是有點複雜的)。
注:雖然說是代碼產生工具,其實一開始Richard也是想的很簡單:就是一個寫文本的操作。
在上面的介面中,選擇要和哪個資料實體類mapping,可以通過選擇“MappingName”來實現。然後點擊“Properties”按鈕,出現了如下的介面:
這是一個專門用來配置mapping的介面:點擊“Add”按鈕,添加一個業務類的屬性,然後用”MappingTo”來設定這個屬性的資料從資料實體類的那個欄位中擷取。在選擇資料實體欄位的時候,也把這個選中資料實體的欄位資訊儲存起來,供給之後的查詢對象使用。
基本思路Richard已經有了。現在的問題就是把上面選選中資料欄位資訊儲存在哪裡,而且還得和業務類的屬性對應,例如,Id對應業務類Product的ProductId,而不是其他的屬性。
在mapping的時候,一般是在業務類中定義一個屬性,然後賦值:
public string ProductId { get; set; }
this.ProductName = productEntity.Id;
為了儲存資料實體欄位的資訊,業務類的屬性聲明就改為下面了:
代碼
public static readonly PropertyInfo<int> ProductIdProperty = RegisterProperty(
typeof(Product),
new PropertyInfo<int>("ProductId",typeof(M_Product)","Id"));
public string ProductId
{ get { return ReadProperty(ProductIdProperty); }
set { LoadProperty(ProductIdProperty, value); }
}
上面的代碼通過產生的方式就比較方便,而且上面的屬性聲明還有更多其他的用途。初一看和WPF中相依性屬性很像,確實思路也是從WPF借鑒而來的。這裡簡稱“Mapping屬性”。
今天就寫到這裡,真是對不住大家,因為本篇寫的比較的囉嗦,而且還沒有寫完。下篇講述Mapping屬性的實現原理和原因,就是為什麼要是用ProductIdProperty那種聲明方式。
著作權為小洋和部落格園所有,歡迎轉載,轉載請標明出處給作者。
http://www.cnblogs.com/yanyangtian