表达式树序列化器

Joc*_*ner 5 c# linq wcf serialization

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

为此,我想使用:http://expressiontree.codeplex.com/

但我想再次执行它们自己的WCF调用.

这意味着我在WCf方面有一个电话:

ImageDTO[] GetImages(XElement exp);
Run Code Online (Sandbox Code Playgroud)

我现在希望在客户端有一个IQueryable(我可以在其上执行Linq表达式),并且我在Serverside上有一个IQueryable(从我的数据访问层,我希望执行序列化表达式).

但我不知道该怎么做,我没有找到任何例子......

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

也许有人可以帮助一个例子.

Nic*_*ler 3

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;
Run Code Online (Sandbox Code Playgroud)

然后,您可以序列化表达式,将其喷射到线路上,然后反序列化。


那么问题是表达式树是基于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;
}
Run Code Online (Sandbox Code Playgroud)

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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

调用它很简单:

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

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

IQueryable query = FixupExpressionTree( ctx, entityType, expression );
Run Code Online (Sandbox Code Playgroud)