LINQ to Entities不识别方法

10

我有以下这些方法:

   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委托的问题。 - Naor
4个回答

15
使用linq-to-entities时,您不能在查询中使用任意的.NET方法。查询中使用的每个方法都必须可翻译为SQL。返回Expession<Func<entityType, bool>>也没有帮助,因为where条件必须在数据库服务器上为每条记录进行评估。
对于EF而言,您的代码意味着:
SELECT COUNT(*)
FROM ...
LEFT JOIN ...
WHERE IsMatch(....) 

因为 EF 验证传递给查询的函数名称,所以它会抛出异常,因为它不知道 SQL 服务器上的 IsMatch 等效函数。
在 Linq-to-entities 中可以使用的唯一可能的函数是:
- 具有预定义映射到 SQL 等效项的规范函数 - EdmFunctions
EdmFunctions 是使用 EdmFunctionAttribute 标记的方法,它将 .NET 函数映射到 SQL 对应项。这些函数通常无法在普通 .NET 代码中执行,因为它们什么也不做或抛出异常。它们只是用于 Linq-to-entities 的函数占位符。可用的 EdmFunctions 如下:
- System.Data.Objects.EntityFunctions 中的预定义 EdmFunctions - System.Data.Objects.SqlClient.SqlFunctions 中 SQL Server(非紧凑型)的预定义 EdmFunctions - 自定义映射 SQL 函数 - 导入向导中的 Entity 设计器允许您导入 SQL 函数(除表值函数外)。之后,您可以编写自定义静态 .NET 函数,并通过 EdmFunction 属性将其映射到导入到设计器中的 SQL 函数。 - 自定义模型定义函数 - 这是手动编写的 EDMX 文件中的特殊函数。它是 Entity SQL 的自定义可重用部分。

我已经在另一个回答中描述了如何创建模型定义函数。创建映射的SQL函数非常相似。您只需将EdmFunctionAttribute属性映射到导入的SQL函数,而不是手动在EDMX中创建Function元素。


2

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

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


LINQ to Entities 不知道如何将 IsMatch 转换为 SQL。您需要使用表达式树来替换它。 - SLaks
4
你的意思是“用表达式树来替换它”是什么意思? - Naor

0

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

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

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

我现在能想到的唯一建议就是使用某种动态表达式锻造来动态创建此查询。或者重新设计您的设计以获得不同的结果。

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

  1. IsMatch方法设置为静态方法。
  2. 直接从IsMatch返回Expression<{your entity here}, bool>
  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));

您能提供一个示例吗?我不明白您最后两步的意思。 - Naor
你编写的静态IsMatch方法是否必须返回不基于其他函数的委托?例如,我可以使用"return i => i.MyMethod(id);"吗? - Naor
不,你必须要么完全创建它作为表达式,要么像Ladislav所说的那样,将你的函数映射到存储过程。 - Euphoric

0

我曾经遇到过类似的问题。解决方法是在使用自定义方法之前使用.AsEnumerable()。你可以在这里查看


1
添加AsEnumerable将整个表加载到内存中,而在companyId的过滤之后,我仍然有很多结果。 - Naor
@Naor:好的,那么,它对我有效,因为我只处理了少量结果。不知道你的情况。 - Damb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接