2013-04-08 7 views
5

Ich möchte Linq Expressions auf Client-Seite verwenden, serialisieren und auf der Server-Seite ausführen.Expression Tree Serializer

Dafür ich verwenden möchte: http://expressiontree.codeplex.com/

Aber ich möchte, dass sie ausführen agains ein eigenes WCF Anruf.

Das heißt, ich habe ein Gespräch auf WCf Seite:

ImageDTO[] GetImages(XElement exp); 

Ich mag jetzt einen IQueryable auf Client-Seite haben (wo ich Linq Ausdrücke ausführen), und ich habe eine IQueryable auf Serverside (von meine Datenzugriffsschicht, auf der ich den serialisierten Ausdruck ausführen möchte).

Aber ich bin nicht sicher, wie dies zu tun, und ich finde keine Beispiele ...

Auf Client-Seite Ich denke, ich Abfrage in einer Klasse implementieren sollte, diese Klasse I im Constructor sagen Verwenden meiner Implementierung von QueryProvider (von wo ich den WCF-Dienst aufrufen). Aber ich bin mir nicht sicher, ob das korrekt ist ...

Vielleicht kann jemand mit einem Beispiel helfen.

+1

ich dies weiß, ist keine Antwort auf Ihre Frage, aber aus Erfahrung, ich würde das nicht tun und stattdessen spezielle Business-Service schreiben. Sie erhöhen die Komplexität und ermöglichen Ihren Clients, das System mit fehlerhaften Abfragen zu überlasten. –

Antwort

2

eine Implementierung von IQueryable<T> im Rahmen Es gibt - MSDN: EnumerableQuery<T>

Wenn Sie dies auf dem Client verwenden können, um die Abfrage zu erstellen, können Sie den gesamten Ausdruck Baum aus der IQueryable<T>.Expression Eigenschaft erhalten.

Sie müssen dies testen, um zu sehen, ob es mit diesem Expression Tree Serializer funktioniert.

Sie können dann den Ausdruck serialisieren, über die Leitung spritzen und dann deserialisieren.


Dann ist das Problem, dass der Ausdruck Baum auf einem EnumerableQuery<T> basiert.

So müssen Sie das von Ihrem mit Ihrer IQueryable<T> Quelle ersetzen echten DbContext

Dies wird ein Bit chaotisch, aber ich habe eine Implementierung geschrieben ein 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; 
} 

verwenden und die ExpressionVisitor selbst:

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 ist dies einfach:

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

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

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

Okay, und wenn ich den Ausdruck serialisiert und auf dem Server Deserialisiert habe, wie führe ich ihn dann gegen meine IQueryable aus, die ich von meiner DL-Ebene habe? –

+0

Jochen: YourIQueryable.Provider.CreateQuery (receivedExpression) .ToList() –

+0

@ JochenKühner Sorry für die Verzögerung. Ich habe meinen Beitrag aktualisiert, um Ihren Kommentar zu beantworten. –