为什么我的表达式树不能识别我的自定义方法?

时间:2014-01-31 20:54:57

标签: c# linq entity-framework expression-trees

我最近在how to write customized expression tree上发了一个问题(虽然我没有意识到那是我当时要求的)。现在我试图使用Scott Chamberlain提供的答案来创建另一种通用方法。

我正在使用Entity Framework并且有几个可以通过“Name”属性过滤的实体。它并不总是名为Name,但基本上就是它。

实际的过滤方法比简单的包含或开始更复杂。它更像是一个Starts With,然后将包含搜索文本的名称的任何记录追加到列表的末尾。

由于有太多实体需要执行此过滤器,我希望能够创建一个将该过滤器应用于预编译查询的扩展方法。

我希望能够致电

    someQuery.ContainsName(x => x.Name, filter.Name);

我有一个看起来像这样的扩展方法

      public static IQueryable<T> ContainsName<T>(this IQueryable<T> query, Expression<Func<T, string>> selector, string matchingName)
    {
        var name = Expression.Constant(matchingName);

        var selectorBody = selector.Body;
        var propertyName = (selectorBody as MemberExpression).Member.Name;
        var propExpression = Expression.Parameter(typeof(string), propertyName);

        var selectorParameters = selector.Parameters;

        Expression check = Expression.Call(typeof(GenericNameFilter).GetMethod("IsMatch"), propExpression, name);

        var lambada = Expression.Lambda<Func<T, bool>>(check, selectorParameters);

        return query.Where(lambada) 
    }

IsMatch只接受2个字符串并返回一个bool。这不是该方法的最终游戏,但我希望能够让IsMatch的简单版本正常工作,然后我会扩展它。

当我在结果上调用ToList时,我得到一个异常。

“LINQ to Entities无法识别方法'Boolean IsMatch(System.String,System.String)'方法,并且此方法无法转换为商店表达式。”

从我所做的搜索中,我相信我想要做的事情是可能的,我只是做错了。这是我设置表达式树的方式吗?是IsMatch方法吗?一切都是错的吗?

1 个答案:

答案 0 :(得分:5)

问题的关键在于你不能编写导致代码运行的查询操作,因为数据库显然无法在其数据上运行C#代码。

您的扩展方法会向查询管道添加lambda调用;你打算将它解决为IsMatch方法的一些重载。但是,这对数据库没有任何意义,因此EF查询提供程序会告诉您它无法转换您写入SQL的内容。不幸的是,没有办法解决这个问题。

相同的代码在LINQ to对象上运行得很好,因为在那种情况下编译器当然可以安排调用你的方法。