1. 程式人生 > 其它 >使用操作符過載,生成ORM實體類的SQL條件語句

使用操作符過載,生成ORM實體類的SQL條件語句

ORM框架的一個不可或缺的功能就是根據實體類,生成操作資料庫的SQL語句,這其中,最難處理的就是那些複雜的SQL條件比較語句。比如,有下面這樣一個SQL語句:

SELECT [id],[BankCode],[CityCode],[FundCode],[FundName],[FundReviews],[EndDagte],[addDate]
 FROM [FundReviews]
    WHERE  ( 
             ([CityCode]=@CP1 OR [BankCode]=@CP2)  
        AND  ([FundCode]=@CP3 OR [BankCode]=@CP4) 
           )

這個複雜的查詢條件由兩個OR子條件最後組合成一個AND 條件的,因此它有3組條件:

1:[CityCode]=@CP1 OR [BankCode]=@CP2;

2:[FundCode]=@CP3 OR [BankCode]=@CP4;

3:1 AND 2 ;

而條件1其實就是 Condition1 OR Condition2,這又是一個條件組合。

我們發現,儘管SQL的條件語句可能很複雜,但這些條件卻是由一些子條件組合成的,或者說由一組條件組合成一個新的條件,大家想想,這是不是典型的“組合模式”阿?

在PDF.NET框架的ORM元件中,有一個專門處理條件的物件OQLCompare ,它就是根據“組合模式

”設計的,我們來看看怎麼由它來構造這個查詢條件:

1,採用AND,OR過載:

FundReviews p = new FundReviews();//例項化一個實體類
OQL q = new OQL(p);               //例項化一個OQL物件
Console.WriteLine("OQLCompare 複雜比較條件表示式測試---------");
OQLCompare cmp = new OQLCompare(p);
OQLCompare cmpResult = (cmp.Comparer(p.CityCode, OQLCompare.CompareType.Equal, "021")
                | cmp.Comparer(p.BankCode, OQLCompare.CompareType.Equal, "008"))
                & (cmp.Comparer(p.FundCode, OQLCompare.CompareType.Equal, "KF008")
                | cmp.Comparer(p.BankCode, OQLCompare.CompareType.Equal, "008"));
           
q.Select().Where(cmpResult);
Console.WriteLine("SQL=" + q.ToString());

在OQL中,採用了類似SQL的語法,也是

Select([屬性列表]).Where([條件表示式]).OrderBy([排序欄位]).GroupBy([分組欄位])

其中[條件表示式]就可以使用OQLCompare物件來構造。由於OQLCompare物件Comparer函式返回的仍然是一個OQLCompare物件,所以可以利用這個特點,採用組合模式,構造出非常複雜的SQL條件語句。

我們看到OQL採用了類似函式式的語法風格,但在[條件表示式]的構造過程中,還是顯得很冗長,我們可以繼續對OQLCompare物件進行重構:

/// <summary>
        /// 設定等於某個實體屬性的比較條件
        /// </summary>
        /// <param name="compare">當前實體比較物件</param>
        /// <param name="Value">要比較的值</param>
        /// <returns>構造的實體比較物件</returns>
        public static OQLCompare operator ==(OQLCompare compare, object Value)
        {
            return BuildOperator(compare, Value, " = ");
        }
        /// <summary>
        /// 設定不等於某個實體屬性的比較條件
        /// </summary>
        /// <param name="compare">當前實體比較物件</param>
        /// <param name="Value">要比較的值</param>
        /// <returns>構造的實體比較物件</returns>
        public static OQLCompare operator !=(OQLCompare compare, object Value)
        {
            return BuildOperator(compare, Value, " <> ");
        }
     /// <summary>
        /// 根據實體物件的屬性,獲取新的條件比較物件
        /// </summary>
        /// <param name="field"></param>
        /// <returns></returns>
        public OQLCompare Property(object field)
        {
            OQLCompare cmp = new OQLCompare();
            cmp.CompareString = this.currPropName ;
            return cmp;
        }
        private static OQLCompare BuildOperator(OQLCompare compare, object Value,string operatorString)
        {
            string paraName = compare.GetNewParameterName();
            compare.CompareString += operatorString + paraName;
            compare.compareValueList.Add(paraName.Substring(1), Value);
            return compare;
        }

我們可以採用類似的方式,繼續實現 >=,>,<=,< 等SQL條件比較符號的過載,這裡就不一一舉例了,我們來看新的使用方式:

2,採用SQL比較符號的過載:

//物件 p 為實體類
OQLCompare cmp2 = new OQLCompare(p);
OQLCompare cmpResult2 = 
               ( cmp2.Property(p.CityCode) == "021"  | cmp2.Property(p.BankCode) == "008")
               &  
               ( cmp2.Property(p.FundCode) == "KF008"| cmp2.Property(p.BankCode) == "008");

q.ReSet();//重新初始化OQL
q.Select().Where(cmpResult2);
Console.WriteLine("操作符過載 SQL=" + q.ToString());

現在這個SQL條件的構造過程是不是清晰多了?這就是操作符過載的魅力:)

3,使用Equal方法,簡化相等比較

直接看下面的程式碼,功能跟上面的例子一樣:

//物件 p 為實體類
OQLCompare cmp2 = new OQLCompare(p);
OQLCompare cmpResult2 = 
               ( cmp2.Equal(p.CityCode,"021")    | cmp2.Equal(p.BankCode,"008")  )
               &  
               ( cmp2.Equal(p.FundCode,"KF008")  | cmp2.Equal(p.BankCode,"008")  );
q.ReSet();//重新初始化OQL
q.Select().Where(cmpResult2);
Console.WriteLine("操作符過載 SQL=" + q.ToString());

從效能上來說,這種方式效率稍高,因為它是函式式的處理方式,更直接。

-------------------------------------------------------------------------

注:本文介紹的這個OQL特性僅在PDF.NET Ver 4.3版本受支援,但之前的版本參照本文說的方法加以改進,也可以使用。有關PDF.NET的版本資訊,請看官網介紹: http://www.pwmis.com/sqlmap 有關PDF.NET的開源資訊,請參看我的部落格文章:

節前送禮:PDF.NET(PWMIS資料開發框架)V3.0版開源