上一篇中,我們分析了實體類的基類Entity,這一篇中,我們就分析一下基於該類的實體類。
每一個實體類都會有兩個檔案組成,我們以BlogClass為例,該類包含兩個檔案:BlogClass.cs和BlogClass.designer.cs,這非常類似VS自己產生的程式碼,更方便的是,VS還會自動把這兩個檔案摺疊起來,。
這兩個檔案中,BlogClass.designer.cs包含所有的產生代碼:成員、屬性等,而BlogClass.cs則只包含一個類的定義,供我們填寫代碼使用。
BlogClass.designer.cs的代碼如下。
1: using System;
2: using System.Collections.Generic;
3: using System.Data.Linq;
4: using System.Linq;
5: using System.Text;
6:
7: using DongBlog.Common;
8:
9: namespace DongBlog.Business.Blogs
10: {
11: /// <summary>
12: /// 日誌分類
13: /// </summary>
14: public partial class BlogClass
15: {
16: #region ID和時間戳記
17:
18: private int _ID = NEW_ENTITY_ID;
19: private byte[] _TimeStamp = new byte[] { };
20:
21: /// <summary>
22: /// 取得ID
23: /// </summary>
24: public override int ID
25: {
26: get { return _ID; }
27: }
28: /// <summary>
29: /// 取得時間戳記
30: /// </summary>
31: public override byte[] TimeStamp
32: {
33: get { return _TimeStamp; }
34: }
35:
36: #endregion
37:
38: #region 成員
39:
40: private string _Name;
41: private string _Description;
42:
43: #endregion
44:
45: #region 屬性
46:
47: /// <summary>
48: /// 取得或設定名稱
49: /// </summary>
50: public string Name
51: {
52: get { return _Name; }
53: set { _Name = value; }
54: }
55: /// <summary>
56: /// 取得或設定描述
57: /// </summary>
58: public string Description
59: {
60: get { return _Description; }
61: set { _Description = value; }
62: }
63:
64: #endregion
65: }
66: }
從代碼裡可以看到,完全就是對實體XML的翻譯,需要特別指出的是,其中實現了Entity定義的ID和TimeStamp這兩個抽象屬性。
BlogClass.cs的代碼如下:
1: using System;
2: using System.Collections.Generic;
3: using System.Data.Linq;
4: using System.Linq;
5: using System.Text;
6:
7: using DongBlog.Common;
8:
9: namespace DongBlog.Business.Blogs
10: {
11: /// <summary>
12: /// 日誌分類
13: /// </summary>
14: public partial class BlogClass : Entity<BlogClass>
15: {
16: }
17:
18: /// <summary>
19: /// 日誌分類的業務外觀
20: /// </summary>
21: public static class BlogClassExtension
22: {
23: }
24: }
呃……這個更簡單了,完全就是個空的。因為它的用處就是讓我們填寫自己的代碼,現在假設我們有這麼一個功能“設定日誌分類名稱時,如果分類的描述為空白,則將分類的描述設定為其名稱”,那麼我們可以這麼幹:從BlogClass.desinger.cs檔案中,將Name屬性的定義Ctrl+X,Ctrl+V過來,然後改改,修改後的代碼如下:
1: using System;
2: using System.Collections.Generic;
3: using System.Data.Linq;
4: using System.Linq;
5: using System.Text;
6:
7: using DongBlog.Common;
8:
9: namespace DongBlog.Business.Blogs
10: {
11: /// <summary>
12: /// 日誌分類
13: /// </summary>
14: public partial class BlogClass : Entity<BlogClass>
15: {
16: /// <summary>
17: /// 取得或設定名稱
18: /// </summary>
19: public string Name
20: {
21: get { return _Name; }
22: set
23: {
24: _Name = value;
25:
26: if (string.IsNullOrEmpty(_Description))
27: _Description = value;
28: }
29: }
30: }
31:
32: /// <summary>
33: /// 日誌分類的業務外觀
34: /// </summary>
35: public static class BlogClassExtension
36: {
37: }
38: }
這個代碼很好理解,值得一提的是,當描述實體的XML修改後,重建實體代碼時,代碼產生器會判斷BlogClass.cs中是否包含了Name屬性,如果包含了該屬性,則在BlogClass.designer.cs中,就不會再產生了。這是自己寫代碼產生而不用通用代碼產生器的好處——我的地盤我做主。:)
另外一個和實體相關的類是Extension類,顧名思義,該類包含的都是對已有類型的擴充方法,利用C#3.0的擴充方法,可以寫出非常優雅的代碼。例如,我們需要查詢某一個分類的所有Blog,給出的是該分類的ID,我們就可以在BlogExtension類中這麼寫(代碼位於\DongBlog.Business\Blogs\Blog.cs):
1: /// <summary>
2: /// 日誌的業務外觀
3: /// </summary>
4: public static class BlogExtension
5: {
6: /// <summary>
7: /// 根據日誌分類取得日誌
8: /// </summary>
9: /// <param name="query">日誌查詢</param>
10: /// <param name="blogClassID">日誌分類ID</param>
11: /// <returns>該分類下的日誌</returns>
12: public static List<Blog> GetBlogsByClassID(this IQueryable<Blog> query, int blogClassID)
13: {
14: if (query == null)
15: throw new ArgumentNullException("query");
16:
17: return query
18: .Where(b => b.BlogClassID == blogClassID)
19: .OrderByDescending(b => b.UpdateDateTime)
20: .ToList();
21: }
22: }
上面的查詢方法使用Linq實現的,我們還順手做了一個根據更新時間的排序。有了這個方法,我們以後就可以用這樣的方式取得某一個分類的Blog:database.GetDataAccess<Blog>().GetBlogByClassID(1);該方式以後還會進一步簡化為:database.Blogs.GetBlogByClassID(1)。
最後說明一點,以上代碼都是可以測試的,因為我們所有的方法都是使用介面作為參數的,所以我們可以用腳手架(Mock類)偽實現相應的介面,以便對不同輸入和環境下的代碼進行自動化測試,具體方法就不展開了。
下一篇文章我們將分析資料訪問的設計與實現。
代碼下載