【问题标题】:Convert Expression<Func<T,T,bool>> to Expression<Func<T,bool>>将 Expression<Func<T,T,bool>> 转换为 Expression<Func<T,bool>>
【发布时间】:2013-06-07 13:26:23
【问题描述】:

我有这样的表达方式

(a,b) => a.Id == b.Id

我想在 LINQ to Entities 查询中使用它

T GetSingle(IRepository<T> repository, Func<T,T,bool> predicate, T entity)
{
   return repository.GetAll().Single(e => predicate(e, entity))
}

但这会导致异常:LINQ to Entities 不支持 LINQ 表达式节点类型“Invoke”
据我了解,我可以使用表达式为 LINQ2SQL 构造一个有效谓词,所以我的表达式 (a,b) => a.Id == b.Id 和具有 Id = 5 的实体实例可以产生新的表达式 (a) => a.Id == 5.
最后一个表达式适用于 LINQ to Entities。

我找到并阅读了这篇文章
Replace parameter in lambda expression
http://www.codeproject.com/Articles/143096/Parameter-Substitution-within-Expression-Trees
但仍然不知道如何解决我的任务

那么,如何动态转换给定的表达式?

【问题讨论】:

    标签: c# linq-to-entities


    【解决方案1】:

    你为什么不把你的方法改成:

    T GetSingle(IRepository<T> repository, Expression<Func<TSource, Boolean>> predicate)
    {
       return repository.GetAll().Single(predicate);
    }
    

    所以不要这样:

    GetSingle(myRepository, (a,b) => a.Id == b.Id, myEntity);
    

    你应该能够做到这一点:

    GetSingle(myRepository, a => a.Id == myEntity.Id);
    

    【讨论】:

    • 这是理论上的兴趣多于实践。现在有一些空闲时间并想研究表达式。抱歉没有指出,更改方法签名不是解决方案
    【解决方案2】:

    我还没有使用 Linq2SQL 对其进行测试,但在我看来,您应该能够使用表达式访问者来执行此操作并编译表达式以将参数的值写入您提供的表达式中(假设您切换到使用Expression&lt;Func&lt;T, T, bool&gt;&gt; 而不是Func&lt;T, T, bool&gt;) 并创建一个包装器,该包装器本身在GetAll 的结果上调用Enumerable.Single

    访问者(特别是您给出的示例看起来像这样)

    public class VariableSubstitutionVisitor : ExpressionVisitor
    {
        private readonly ParameterExpression _parameter;
        private readonly ConstantExpression _constant;
    
        public VariableSubstitutionVisitor(ParameterExpression parameter, ConstantExpression constant)
        {
            _parameter = parameter;
            _constant = constant;
        }
    
        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node == _parameter)
            {
                return _constant;
            }
    
            return node;
        }
    }
    

    现在,我们将 GetSingle 方法调整为如下所示:

    public T GetSingle(IRepository<T> repository, Expression<Func<T, T, bool>> predicate, T entity)
    {
        //Create a new representation of predicate that will take just one parameter and capture entity
    
        //Get just the body of the supplied expression
        var body = predicate.Body;
        //Make a new visitor to replace the second parameter with the supplied value
        var substitutionVisitor = new VariableSubstitutionVisitor(predicate.Parameters[1], Expression.Constant(entity, typeof(T)));
        //Create an expression that represents the predicate with the second parameter replaced with the supplied entity
        var visitedBody = substitutionVisitor.Visit(body).Reduce();
        //Make the new expression into something that could be a Func<T, bool>
        var newBody = Expression.Lambda<Func<T, bool>>(visitedBody, predicate.Parameters[0]); 
    
        //Now, create something that will call Enumerable.Single on the result of GetAll from the repository, supplying the new predicate
    
        //Make a place to hold the result of GetAll
        var resultsParameter = Expression.Parameter(typeof (IEnumerable<T>));
        //Make an expression that calls the Single extension method
        var singleExpression = Expression.Call(((Func<IEnumerable<T>, Func<T, bool>, T>)Enumerable.Single).Method, resultsParameter, newBody);
        //Make a Func<IEnumerable<T>, T> that return the result of the call of Single on the results of the GetAll method
        var compiled = Expression.Lambda<Func<IEnumerable<T>, T>>(singleExpression, resultsParameter).Compile();
        //Call GetAll, letting the new method that we've got run the supplied predicate without having to run an Invoke type expression
        return compiled(repository.GetAll()); 
    }
    

    当然,诀窍是让它表现良好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-05
      • 2023-03-31
      • 1970-01-01
      相关资源
      最近更新 更多