表达式树序列化器

本文关键字:序列化 表达式 | 更新日期: 2023-09-27 18:08:02

我想在客户端使用Linq表达式,序列化它们并在服务器端执行它们。

我想使用:http://expressiontree.codeplex.com/

但是我想对自己的WCF调用执行它们。

这意味着我在WCf端有一个调用:

ImageDTO[] GetImages(XElement exp);

我现在想有一个IQueryable在客户端(我可以执行Linq表达式),我有一个IQueryable在服务器端(从我的数据访问层,我想在其上执行序列化表达式)。

但我不确定如何做到这一点,我没有找到任何例子…

在客户端,我认为我应该在一个类中实现查询,这个类我在构造函数中告诉使用我的QueryProvider的实现(从那里我调用WCF服务)。但我不确定这是否正确…

也许有人可以帮我举个例子。

表达式树序列化器

框架中有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>的。

所以你需要用DbContext

中的IQueryable<T>源代码来替换它

这得到一个混乱,但我已经写了一个实现使用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 );

为了解决我的问题,我使用了Interlinq,但这是一个我分叉的版本,因此它也可以与Silverlight一起工作。

https://github.com/jogibear9988/Interlinq-2