2013-04-08 64 views
5

我想在客戶端使用Linq表達式,對它們進行序列化並在服務器端執行它們。表達式樹序列化程序

爲此,我想用:http://expressiontree.codeplex.com/

但我要執行這些agains一個自己的WCF呼叫。

這意味着我有WCF側的呼叫:

ImageDTO[] GetImages(XElement exp); 

我現在要對客戶機端的IQueryable(關於這一點我可以執行LINQ表達式),和我有Serverside集團一IQueryable的(從我的數據訪問層,我想要執行序列化表達式)。

但我不知道如何做到這一點,我沒有找到任何的例子...

在客戶端,我想我應該在一個類實現查詢,這個類我告訴在構造函數使用我的QueryProvider實現(從我稱之爲WCF服務的地方)。但我不確定這是否正確...

也許有人可以幫助一個例子。

+1

我知道這是不是一個回答你的問題,但是從經驗,我不會這麼做,而是寫竭誠爲企業服務。您增加了複雜性,並允許您的客戶端以不良的查詢來降低系統性能。 – 2013-04-23 11:05:11

回答

2

還有的IQueryable<T>在框架的實現 - MSDN: EnumerableQuery<T>

如果您可以使用此客戶端上,以構建查詢,你可以從IQueryable<T>.Expression財產整個表達式樹。

您將不得不測試它以查看它是否適用於該表達式樹序列化器。

var iQueryable = new EnumerableQuery<Model>(Enumerable.Empty<Model>()); 

var query = iQueryable.Include(...).Where(...).OrderBy(...); 

var expressionTree = query.Expression; 

然後,您可以序列化表達式,將它噴射到電線上,然後反序列化它。


然後問題是表達式樹是基於EnumerableQuery<T>

所以,你需要與你的IQueryable<T>源代替從你的真實DbContext

這得到了凌亂,但我已經寫了使用ExpressionVisitor:

IQueryable FixupExpressionTree(ObjectContext ctx, Type entityType, Expression expression) 
{ 
    var tObjectContext = ctx.GetType(); 
    var mCreateObjectSetOpen = tObjectContext.GetMethod("CreateObjectSet", new Type[ 0 ]); 
    var mCreateObjectSetClosed = mCreateObjectSetOpen.MakeGenericMethod(entityType); 

    var objectQuery = (ObjectQuery) mCreateObjectSetClosed.Invoke(ctx, null); 

    var eFixed = new Visitor(objectQuery, entityType).Visit(expression); 

    var qFixed = ((IQueryable) objectQuery).Provider.CreateQuery(eFixed); 

    return qFixed; 
} 

ExpressionVisitor實現本身:

public class Visitor : ExpressionVisitor 
{ 
    ObjectQuery _Source = null; 
    Type _EntityType = null; 

    public Visitor(ObjectQuery source, Type entityType) { _Source = source; _EntityType = entityType; } 

    protected override Expression VisitConstant(ConstantExpression node) 
    { 
     if (!node.Type.Name.Contains("EnumerableQuery")) return base.VisitConstant(node); 

     var eConstantInstance = Expression.Constant(_Source); 
     var eConstantArgument = Expression.Constant(MergeOption.AppendOnly); 

     var tObjectQueryOpen = typeof(ObjectQuery<>); 
     var tObjectQueryClosed = tObjectQueryOpen.MakeGenericType(_EntityType); 
     var eMergeAsMethod = tObjectQueryClosed.GetMethod("MergeAs", BindingFlags.Instance | BindingFlags.NonPublic); 

     return Expression.Call(eConstantInstance, eMergeAsMethod, eConstantArgument); 
    } 
} 

Calli NG,這是直截了當:

Type entityType = ... 
Expression expression = ... 
DbContext db = ... 

ObjectContext ctx = ((IObjectContextAdapter) db).ObjectContext; 

IQueryable query = FixupExpressionTree(ctx, entityType, expression); 
+0

好的,當我序列化表達式,並在服務器上反序列化時,我如何執行它反對我從我的DL層獲得的IQueryable? – 2013-04-08 21:13:44

+0

Jochen:YourIQueryable.Provider.CreateQuery (receivedExpression).ToList() – 2013-04-23 08:40:06

+0

@JochenKühner對不起,延遲。我更新了我的帖子以回答您的評論。 – 2013-04-23 10:57:09