【问题标题】:linq to entities doesn't recognize a methodlinq to entity 无法识别方法
【发布时间】:2011-05-01 02:25:34
【问题描述】:

我有这些方法:

   public int count(
        Guid companyId, Expression<Func<T, bool>> isMatch)
    {
        var filters = new Expression<Func<T, bool>>[]{
            x => x.PriceDefinition.CompanyId == companyId,
            isMatch
        };

        return GetCount(filters);
    }

public virtual int GetCount(
            IEnumerable<Expression<Func<T, bool>>> filters)
        {
            IQueryable<T> _query = ObjectSet;

            if (filters != null)
            {
                foreach (var filter in filters)
                {
                    _query = _query.Where(filter);
                }
            }

           return _query.Count();
        }

使用时:

count(some_guid, x => x.IsMatch(entityId, inviterId, routeId, luggageTypeId));

我得到以下异常:

LINQ to Entities does not recognize the method 'Boolean IsMatch(System.Nullable`1[System.Int64], System.Nullable`1[System.Int64], System.Nullable`1[System.Int64], System.Nullable`1[System.Int64])' method, and this method cannot be translated into a store expression.

这是什么原因?
我该如何解决?

【问题讨论】:

  • @SLaks♦:对不起,我用 isMatch 代表更新了问题。

标签: c# .net entity-framework linq-to-entities


【解决方案1】:

使用 linq-to-entities 时,您不能在查询中使用任意 .NET 方法。查询中使用的每个方法都必须可转换为 SQL。返回Expession&lt;Func&lt;entityType, bool&gt;&gt; 对您没有帮助,因为必须为数据库服务器上的每条记录评估 where 条件。

对于 EF,您的代码意味着:

SELECT COUNT(*)
FROM ...
LEFT JOIN ...
WHERE IsMatch(....) 

因为 EF 验证传递给查询的函数名称,所以它会抛出异常,因为它不知道 SQL 服务器上的 IsMatch 等效项。

可以在 Linq-to-entities 中使用的唯一可能的函数是:

EdmFunctions 是用EdmFunctionAttribute 标记的方法,它将 .NET 函数映射到 SQL 对应项。这些函数通常不能在通用 .NET 代码中执行,因为它们什么都不做或抛出异常。它们是 Linq-to-entities 的唯一功能占位符。可用的 EdmFunction 有:

  • System.Data.Objects.EntityFunctions 中的预定义 EdmFunctions
  • System.Data.Objects.SqlClient.SqlFunctions 中 SQL Server 的预定义 EdmFunctions(非压缩)
  • 自定义映射 SQL 函数 - 实体设计器中的导入向导允许您导入 SQL 函数(表值函数除外)。之后,您可以编写自定义静态 .NET 函数并通过 EdmFunction 属性将其映射到导入到设计器的 SQL 函数。
  • 自定义模型定义函数 - 这是在 EDMX 文件(以 XML 格式打开)中手动编写的特殊函数。它是 Entity SQL 的自定义可重用部分。

我已经在另一个答案中描述了how to create model defined function。创建映射的SQL function is pretty similar。您无需在 EDMX 中手动创建 Function 元素,而是将 EdmFunctionAttribute 属性映射到导入的 SQL 函数。

【讨论】:

    【解决方案2】:

    您正在传递一个调用名为 IsMatch 的函数的表达式。

    LINQ to Entities 不知道如何处理此函数。

    【讨论】:

    • LINQ to Entities 不知道如何将 IsMatch 转换为 SQL。您需要将其替换为表达式树。
    • ♦:“用表达式树替换它”是什么意思?
    【解决方案3】:

    我正在处理类似的问题。在尝试使用我的自定义方法之前,工作解决方案是使用.AsEnumerable()。你可以take a look at it here

    【讨论】:

    • 添加 AsEnumerable 会将整个表加载到内存中,经过 companyId 的过滤后我仍然有很多结果..
    • @Naor:好吧,它对我有用,因为我的工作结果很少。不知道你的。
    【解决方案4】:

    实际上,你传递给 count 的函数看起来像这个函数:

    bool anonymous_delagate#123(T entity)
    {
        return entity.IsMatch(a,b,c,d)
    }
    

    但是,这需要 EF 知道,在此实体上调用的方法 IsMatch 的真正含义是什么。

    我现在唯一能想到的建议是使用某种动态表达式伪造来动态创建此查询。或者重新设计你的设计以做出不同的选择。

    其实有一种更简单、更正常的方法,只需几个步骤即可完成。

    1. 将方法IsMatch设为静态。
    2. 直接从IsMatch返回Expression&lt;{your entity here}, bool&gt;
    3. 像这样传递它:({your entity here}.IsMatch({parameters}))

    休息可以和现在一样。

    编辑:示例 这将适用于特定实体,因此我假设您的实体是 Order。替换您自己的实体。

    public static Expression<Func<Order, bool>> IsMatch(int id, ...) // static method, that returns filtering expression
    {
         return i => i.Id == id; // create the filtering criteria
    }
    

    然后这样称呼它:

    count(some_guid, Order.IsMatch(entityId, inviterId, routeId, luggageTypeId));
    

    【讨论】:

    • 你能提供一个例子吗?我不明白你的最后两个步骤。
    • 您编写的静态 IsMatch 方法是否必须返回不基于其他函数的委托?我可以使用例如“return i => i.MyMethod(id);”吗?
    • 没有。您必须使用 eiter 将其完全创建为表达式,或者像 Ladislav 所说的那样,将您的函数映射到存储过程。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多