I want to use Linq Expressions on Client Side, Serialize them and Execute them on server Side.
For this I want to use: http://expressiontree.codeplex.com/
But I want to Execute them agains a own WCF Call.
That means i Have a Call on WCf Side:
ImageDTO[] GetImages(XElement exp);
I now want to have a IQueryable on Client Side (on which I can execute Linq Expressions), and I have a IQueryable on Serverside (from my data acess layer, on wich i want to execute the serialized expression).
But I'm not sure how to do this, and I don't find any Examples...
On Client Side i think I should implement Query in a Class, this class I tell in the Constructor to use my implementation of QueryProvider (from where I call the WCF Service). But I'm not sure if this is correct...
Maybe someone can help with a Example.
There's an implementation of IQueryable<T>
in the framework - MSDN: EnumerableQuery<T>
If you can use this on the client to build the query, you can get the whole Expression Tree from the IQueryable<T>.Expression
property.
You'll have to test this to see if it works with that Expression Tree Serializer.
var iQueryable = new EnumerableQuery<Model>( Enumerable.Empty<Model>() );
var query = iQueryable.Include( ... ).Where( ... ).OrderBy( ... );
var expressionTree = query.Expression;
You can then serialize the expression, squirt it accross the wire and then deserialize it.
Then the problem is that the expression tree is based on an EnumerableQuery<T>
.
So you need to replace that with your IQueryable<T>
source from your real DbContext
This gets a bit messy, but I've written an implementation using an 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;
}
and the ExpressionVisitor
itself:
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 );
}
}
Calling this is straight forward:
Type entityType = ...
Expression expression = ...
DbContext db = ...
ObjectContext ctx = ( ( IObjectContextAdapter ) db ).ObjectContext;
IQueryable query = FixupExpressionTree( ctx, entityType, expression );
To Solve my Problem, I used Interlinq, but a Version wich I forked, so that it also works with Silverlight.
https://github.com/jogibear9988/Interlinq-2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With