使用操作符過載,生成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版開源