我想在客户端使用Linq Expressions,将它们序列化并在服务器端执行它们。
为此,我想使用:http://expressiontree.codeplex.com/
但我想再次执行它们自己的WCF调用。
这意味着我在WCf方面有一个电话:
ImageDTO[] GetImages(XElement exp);
我现在希望在客户端有一个IQueryable(我可以在其上执行Linq表达式),并且我在Serverside上有一个IQueryable(从我的数据访问层,我希望执行序列化表达式)。
但我不知道该怎么做,而且我找不到任何例子......
在客户端我认为我应该在一个类中实现Query,这个类我在构造函数中告诉我使用我的QueryProvider实现(从我调用WCF服务的地方)。但我不确定这是否正确...
也许有人可以帮助举例。
答案 0 :(得分:3)
框架中有IQueryable<T>
的实施 - MSDN: EnumerableQuery<T>
如果您可以在客户端上使用它来构建查询,则可以从IQueryable<T>.Expression
属性获取整个表达式树。
您必须对此进行测试以查看它是否适用于Expression Tree Serializer。
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 );
}
}
直接呼吁:
Type entityType = ...
Expression expression = ...
DbContext db = ...
ObjectContext ctx = ( ( IObjectContextAdapter ) db ).ObjectContext;
IQueryable query = FixupExpressionTree( ctx, entityType, expression );
答案 1 :(得分:1)
为了解决我的问题,我使用了Interlinq,但是我分叉了一个版本,因此它也适用于Silverlight。