Apply SOA Design Patterns with WCF (4) WCF Database Paging & Sorting (數據庫端分頁和排序)
Original (原創) by Teddy’s Knowledge Base
Content (目錄)
(1) WCF Configuration Centralization (WCF配置集中管理)
(2) WCF Automatic Deployment (WCF自動化部署)
(3) WCF Automatic Service Locating (WCF自動化服務定位)
(4) WCF Database Paging & Sorting (WCF數據庫分頁和排序)
(5) WCF Based ASP.NET DataSouce Control (基于WCF的數據源控件)
(6) 1 + 2 + 3 + 4 + 5 = ?
摘要
本文提供一種支持跨WCF通訊的數據庫端分頁和排序(以及更多超過你預期的功能)方案。
正文
我們在重新發明輪子嗎?
已經有很多數據庫端分頁和排序的實現方案了,從微軟的LINQ to SQL和Entity Framework到無數的ORM框架和基于存儲過程的分頁和排序實現。
但是,構架得很好的支持跨WCF通信的數據庫端分頁和排序方案還很少見到。大多數數據庫端分頁和排序方案要么依賴于不能被序列化的對象,要么暴露了太多SQL相關的信息給客戶端,甚至可能允許客戶程序直接構造SQL或偽SQL片段,這樣就不能很好的避免SQL注入。
所以,我們是在創新而不是重新造輪子。
我們的目標
下面是這個跨WCF通信的分頁排序方案的功能列表:
- LINQ風格的強類型查詢語言
- 支持分頁和排序
- 支持常用的數據庫操作和方法
- 避免SQL注入
- 隱藏數據結構和SQL的細節
- 查詢對象能改能跨WCF通信
- 多數據庫查詢語言擴展支持
- 支持和第三方詩句訪問組件和ORM類庫的整合
類圖
各個類的職責
- Criteria – 主要的攜帶關于一個查詢的所有信息的類
- IExpression – 所有構成Criteria的元素的接口
- Expression類– 代表查詢中不同類型的表達式
- Parameter Expression類 – 代表不同類型的參數,每個參數包裝了一個原生類型的數據值
- IColumn – 所有Column表達式的接口
- Column類 – 代表查詢中不同類型的Column
- Condition – 代表一個邏輯表達式,可以參與諸如And,Or,Not這樣的邏輯操作
表達式的操作和方法
- 常用的操作和方法應該定義為類的公共方法,并且,如果可能,為每個操作也定義相應的操作符重載
- 對特定數據庫的操作和方法應該要么定義在繼承的子類中,要么定義為擴展方法
查詢示例代碼
1 public class TestCriteria : Criteria
2 {
3 public TestCriteria()
4 : base("TestTable", "Test")
5 {
6 }
7
8 public BooleanColumn BooleanColumn = new BooleanColumn("BooleanColumn");
9 public ByteColumn ByteColumn = new ByteColumn("ByteColumn");
10 public Int16Column Int16Column = new Int16Column("Int16Column");
11 public Int32Column Int32Column = new Int32Column("Int32Column");
12 public Int64Column Int64Column = new Int64Column("Int64Column");
13 public DateTimeColumn DateTimeColumn = new DateTimeColumn("DateTimeColumn");
14 public StringColumn StringColumn = new StringColumn("StringColumn", true);
15 public GuidColumn GuidColumn = new GuidColumn("GuidColumn");
16 public DoubleColumn DoubleColumn = new DoubleColumn("DoubleColumn");
17 public DecimalColumn DecimalColumn = new DecimalColumn("DecimalColumn");
18 }
19
20 var criteria = new TestCriteria();
21 criteria.MaxResults(10).AddSortBy(criteria.Int32Column, true).AddSortBy(criteria.StringColumn, false);
22 criteria.And(criteria.Int32Column == 1).Or(criteria.StringColumn.Like("test"));
23
24 criteria.AddResultColumn(DateTimeColumn).AddResultColumn((criteria.Int32Column + 1).As("ID")).AddResultColumn(criteria.StringColumn.As("Name"));
25 criteria.SkipResults(10);
26 criteria.Distinct();
27
28 var queryResult = aWcfService.Query(criteria);
如何使類能夠作為WCF服務的參數被序列化
這些類的結構和上面的查詢示例代碼可能和大多數SQL風格的查詢語言很相似,真正的實現難點其實在如何使他們能夠作為WCF服務的參數被序列化。下面的要點能幫助實現這個目標:
- 除了Criteria的所有的類應該要么定位為sealed類,要么只有internal的構造函數,這樣就能確保在我們定義的程序集之外不會有子類
- 所有的類應該標注為WCF的DataContract,所有的字段應該標注為DataMember
- 所有的類都不應該包含不能被序列化的字段
- 一個類的所有依賴類型都應該被加進這個類的定義的KnownType列表中,例如,因為Criteria類依賴于所有其他的表達式類型,所以,Criteria類的定義應該像下面這樣:
1 [DataContract]
2 [KnownType(typeof(BooleanColumn))]
3 [KnownType(typeof(ByteColumn))]
4 [KnownType(typeof(Int16Column))]
5 [KnownType(typeof(Int32Column))]
6 [KnownType(typeof(Int64Column))]
7 [KnownType(typeof(DateTimeColumn))]
8 [KnownType(typeof(StringColumn))]
9 [KnownType(typeof(GuidColumn))]
10 [KnownType(typeof(DoubleColumn))]
11 [KnownType(typeof(DecimalColumn))]
12 [KnownType(typeof(Condition))]
13 [KnownType(typeof(NullExpression))]
14 [KnownType(typeof(BooleanExpression))]
15 [KnownType(typeof(ByteExpression))]
16 [KnownType(typeof(Int16Expression))]
17 [KnownType(typeof(Int32Expression))]
18 [KnownType(typeof(Int64Expression))]
19 [KnownType(typeof(DateTimeExpression))]
20 [KnownType(typeof(StringExpression))]
21 [KnownType(typeof(GuidExpression))]
22 [KnownType(typeof(DoubleExpression))]
23 [KnownType(typeof(DecimalExpression))]
24 [KnownType(typeof(ExpressionCollection))]
25 [KnownType(typeof(BooleanParameterExpression))]
26 [KnownType(typeof(ByteParameterExpression))]
27 [KnownType(typeof(Int16ParameterExpression))]
28 [KnownType(typeof(Int32ParameterExpression))]
29 [KnownType(typeof(Int64ParameterExpression))]
30 [KnownType(typeof(DateTimeParameterExpression))]
31 [KnownType(typeof(StringParameterExpression))]
32 [KnownType(typeof(GuidParameterExpression))]
33 [KnownType(typeof(DoubleParameterExpression))]
34 [KnownType(typeof(DecimalParameterExpression))]
35 public class Criteria
36 {
37 //…
38
39 }
第三方數據訪問和ORM類庫整合
因為上面討論的類都不是只能用于特定數據庫訪問組件的,所以,一個criteria可以被認為是一個查詢的元數據,可以被翻譯為任意一個實際的數據訪問實現。例如,翻譯成LINQ to SQL查詢語言或者翻譯成一個能直接執行的DbCommand。
基于Criteria的WCF服務的好處
- 支持復雜條件的查詢
- 更容易的支持分頁和排序
- 極大的減少數據庫風格的查詢類型的服務的數量
提示
- 無論LINQ還是這種強類型的查詢語言都有額外的運行時消耗,包括構造criteria和翻譯成實際的數據訪問語言的內存、CPU運行時間消耗。所以對高性能場景,存儲過程還是應該是數據庫查詢類服務首選的實現方案。
- 在實踐中,對企業級應用來說,一般,除了專門用來實現并不容易實現的分頁和排序功能,這種基于Criteria的WCF服務更多的還是用來實現原型程序和被用來在最終的應用中作為一個后備服務。我還是會定義包含清晰的業務含義名稱的服務,如LoadByID(),GetAllXXX(),并且只要可能就用存儲過程來實現。
參考
(1) SOA Design Pattern Catalog: http://www.soapatterns.org///我是結尾符,待續…

浙公網安備 33010602011771號