【问题标题】:Why doesnt my Expression Tree recognize my custom method?为什么我的表达式树无法识别我的自定义方法?
【发布时间】:2014-02-01 05:07:58
【问题描述】:

我最近在how to write customized expression tree 上发布了一个问题(尽管我当时没有意识到这是我在问的问题)。现在我正在尝试使用 Scott Chamberlain 提供的答案来创建另一个通用方法。

我正在使用实体框架,并且有几个实体可以通过“名称”属性之类的东西进行过滤。它并不总是被称为名称,但基本上就是这样。

实际的过滤器方法比简单的包含或开头更复杂。它更像是 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 个字符串并返回一个布尔值。这并不是该方法的最终结果,但我希望能够让一个简单版本的 IsMatch 工作,然后我会对其进行扩展。

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

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

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

【问题讨论】:

  • 否;这是不可能的。 EF 应该如何知道如何将IsMatch(...) 转换为 SQL?
  • 让我感到困惑的是,有一个方法叫做“Call”,它似乎是为了执行这样的方法而设计的。 MSDN 上的示例看起来像 Expression callExpr = Expression.Call( Expression.Constant("sample string"), typeof(String).GetMethod("ToUpper", new Type[] { }));是否只有原生方法可以与 Call 一起使用?
  • 表达式树不是 EF 独有的;它们支持比 EF 更多的功能。但Call() 也用于EntityFunctions

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


【解决方案1】:

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

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

相同的代码可以在 LINQ to 对象上正常运行,因为在这种情况下,编译器当然可以安排调用您的方法。

【讨论】:

  • 我最初以为是这样,但是当查看 Expression.Call 方法时,似乎您可以做到。它需要 MethodInfo 和 1 或属性表达式的某种组合。是否仅限于原生方法?
  • @bsayegh:你能做到什么?将您的方法的代码翻译成 SQL?
  • 好吧,也许不能翻译成 Sql。我很困惑这是如何工作的。我认为 .net 会执行查询,然后在执行 sql 后应用我的代码。
  • @bsayegh:如果这是您想要的,那么您必须使用 IEnumerable&lt;T&gt; 而不是 IQueryable&lt;T&gt;,并完全放弃表达式树。
  • 我之前尝试过使用 IEnumerable,但遇到了一个问题。似乎我需要实现一个具有 Name 属性的接口或基类,以便我的方法知道要查询的属性。虽然我可以将它应用于每个实体,但每次更新数据库映射时都会重新生成类。有没有办法在不使用界面的情况下实现我的目标?
猜你喜欢
  • 1970-01-01
  • 2013-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 2020-05-28
相关资源
最近更新 更多