2013-04-08 2 views
5

Desidero utilizzare Linq Expressions sul lato client, serializzarli ed eseguirli sul lato server.Expression Tree

Per questo voglio usare: http://expressiontree.codeplex.com/

Ma voglio eseguirli contro un proprio WCF chiamata.

Questo significa che ho una chiamata su WCF laterale:

ImageDTO[] GetImages(XElement exp); 

io ora voglio avere un IQueryable sul lato client (su cui posso eseguire Linq Espressioni), e ho un IQueryable su Serverside (da il mio livello di accesso ai dati, su cui voglio eseguire l'espressione serializzata).

Ma io non sono sicuro di come fare questo, e non trovo alcun esempio ...

Sul lato client penso che dovrei implementare query in una classe, questa classe dico nel costruttore utilizzare la mia implementazione di QueryProvider (da dove chiamo il servizio WCF). Ma non sono sicuro che sia corretto ...

Forse qualcuno può aiutare con un esempio.

+1

So che questa non è una risposta alla tua domanda, ma per esperienza, non vorrei fare questo e invece scrivere servizi business dedicati. Si aggiunge complessità e si consente ai client di arrestare il sistema con query non valide. –

risposta

2

C'è un'implementazione del IQueryable<T> nel quadro - MSDN: EnumerableQuery<T>

Se è possibile utilizzare questo sul client per costruire la query, è possibile ottenere l'intero albero di espressione dalla proprietà IQueryable<T>.Expression.

Dovrai testarlo per vedere se funziona con quel Serializer di Expression Tree.

È quindi possibile serializzare l'espressione, spruzzarla attraverso il filo e quindi deserializzare.


allora il problema è che l'albero di espressione si basa su un EnumerableQuery<T>.

Quindi è necessario per sostituire che con la vostra fonte IQueryable<T> dal vero DbContext

Questo diventa un po ' disordinato, ma ho scritto un'implementazione utilizzando un 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; 
} 

e la ExpressionVisitor stesso:

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 questo è semplice:

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

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

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

Ok, e quando ho serializzato l'espressione e deserializzato sul server, come faccio a eseguirlo contro il mio IQueryable che ho dal mio DL Layer? –

+0

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

+0

@ JochenKühner Ci scusiamo per il ritardo. Ho aggiornato il mio post per rispondere al tuo commento. –