好吧,我就招了吧,我是打算發個廣告來著,可又一想,發個純廣告帖上來,肯定罵聲一片,磚頭、雞蛋滿天飛,道不如把DAC中,關於自定義LINQ表達式支援的程式碼講解一下,或許對一些自己寫資料層或想寫些LINQ擴充實用的人會有些幫助,就算沒什麼幫助,那就起到點兒「拋磚引玉」的作用,豈不是也很好!
在DAC的先前版本中,使用以下表達式進行查詢:
IEnumerable<Issue> q = this.dc.Query<Issue>(Issue._.IssueID >= 0);
這個“可愛”的”_”顯得是那樣的“不成熟”,特別是在這個LINQ橫行的時代,顯得特不“與時俱進”。於是就有了DAC擴充LINQ支援的v2.6版。
var q = this.dc.Query<Issue>(s => s.IssueID > 0);
或
var q = from s in (this.dc.GetQueryableData<Issue>())
where s.IssueID > 0
select s;
上面的兩種方法的實現,主要是靠對表達式的解析,組裝SQL語句。老趙的貼文寫的很好,也可以看DAC的源碼(我是置入廣告)。
我今天主要想說的是,如果我們原來有自已的表達式樹及其解析功能,那能不能讓它很容易的「升級」到LINQ的支援呢? !是的,很容易!
var q = from s in SystemUser._
where s.FullName == s.FullName.Max
orderby s.UserID
select s.Except(s.Password);
要相讓一個物件可以被”where”, “orderby”, “select”,那就讓它實現名為”Where”, “OrderBy”, “Select”的方法,或使用Extension Method方式,就像DAC中:
public static class QueryExpressionExtension
{
public static RaisingStudio.Data.Expressions.IQueryExpression<T> Where<T>(
this RaisingStudio.Data.Expressions.IQueryExpression<T> source,
Expression<Func<T, RaisingStudio.Data.Expressions.ConditionExpression>> predicate)
{
return (new RaisingStudio.Data.Expressions.QueryExpression<T>(
source.Value,
source.Table,
(predicate.Compile())(source.Value),
source.Columns));
}
public static RaisingStudio.Data.Expressions.IQueryExpression<T> OrderBy<T>(
this RaisingStudio.Data.Expressions.IQueryExpression<T> source,
Expression<Func<T, RaisingStudio.Data.Expressions.ColumnExpression>> predicate)
{ … }
public static RaisingStudio.Data.Expressions.IQueryExpression<T> Select<T>(
this RaisingStudio.Data.Expressions.IQueryExpression<T> source,
Expression<Func<T, object>> predicate)
{ ... }
}
在方法的實作中,對傳入的「系統」表達式,進行Compile方法調用,即可返回「自訂」的表達式,然後將這些「自訂」的表達式保存在「查詢表達式(QueryExpression )」中,當「查詢」被執行時,就可以直接取出保存下來的「自訂」表達式,這樣,再利用上程式碼原來對「自訂」表達式的解析,就可以實現查詢了! ! !