【问题标题】:Expression Tree Serializer表达式树序列化器
【发布时间】:2013-04-08 19:56:54
【问题描述】:

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

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

但我想通过自己的 WCF 调用再次执行它们。

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

ImageDTO[] GetImages(XElement exp);

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

但我不确定如何执行此操作,也找不到任何示例...

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

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

【问题讨论】:

  • 我知道这不是您问题的答案,但根据经验,我不会这样做,而是编写专门的业务服务。您增加了复杂性,并允许您的客户因错误的查询而导致系统崩溃。

标签: c# wcf linq serialization


【解决方案1】:

框架中有一个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&lt;T&gt;

所以你需要用你真正的DbContext中的IQueryable&lt;T&gt;源替换它

这有点混乱,但我已经使用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 );

【讨论】:

  • 好的,当我序列化表达式并在服务器上反序列化时,如何针对我的 DL 层中的 IQueryable 执行它?
  • Jochen: YourIQueryable.Provider.CreateQuery(receivedExpression).ToList()
  • @JochenKühner 抱歉耽搁了。我已更新我的帖子以回答您的评论。
  • 我认为这可以在我的系统上运行,但我现在使用 Interlinq 解决了它。但我将此标记为答案
  • @JochenKühner 推广您的答案(实际答案)以帮助他人看到会很有帮助。 InterLinq 看起来可以很好地解决您的问题。
【解决方案2】:

为了解决我的问题,我使用了 Interlinq,但我使用了一个 fork 的版本,因此它也适用于 Silverlight。

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

【讨论】:

    猜你喜欢
    • 2014-06-08
    • 2010-09-18
    • 1970-01-01
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-20
    • 1970-01-01
    相关资源
    最近更新 更多