linq to entities не распознает метод

у меня есть эти методы:

   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.

в чем причина этого?
Как я могу ее решить?

4 ответов


при использовании linq-to-entities вы не можете использовать произвольные методы .NET в запросе. Каждый метод, используемый в запросе, должен быть переведен на SQL. Это не поможет вам вернуться Expession<Func<entityType, bool>> потому что условие where должно быть оценено для каждой записи на сервере базы данных.

для EF ваш код означает что-то вроде:

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

поскольку EF проверяет имена функций, переданных в запрос, он выдаст исключение, потому что он не знает эквивалент IsMatch на SQL сервер.

единственными возможными функциями, которые могут использоваться в Linq-to-entities, являются:

  • функции Cannonical с предопределенным сопоставлением с эквивалентом SQL
  • EdmFunctions

EdmFunctions-это методы, отмеченные EdmFunctionAttribute карты .Чистая функция в SQL аналог. Эти функции обычно не могут быть выполнены в общем коде .NET, потому что они ничего не делают или вызывают исключение. Они только держатель места функции для Linq-to-сущностей. Доступные функции EdmFunctions:

  • предопределенные EdmFunctions в System.Data.Objects.EntityFunctions
  • предопределенные EdmFunctions для SQL Server (не компактный) в System.Data.Objects.SqlClient.SqlFunctions
  • пользовательские сопоставленные функции SQL-мастер импорта в Entity designer позволяет импортировать функции SQL (кроме функций с табличным значением). После этого вы можете написать пользовательскую статическую функцию .NET и сопоставить ее с помощью EdmFunction атрибут функции SQL, импортированной в дизайнер.
  • пользовательские функции, определенные моделью - это специальная функция, написанная вручную в файле EDMX (открыт как XML). Это пользовательская многоразовая часть Entity SQL.

Я уже описал как создать модель определенной функции в другой ответ. Создание сопоставляется функция SQL довольно похожа. Вместо ручного создания Function элемент в EDMX вы будете отображать EdmFunctionAttribute свойства импортированной функции SQL.


вы передаете выражение, которое вызывает функцию с именем IsMatch.

LINQ to Entities не знает, что делать с этой функцией.


Я имел дело с подобной проблемой. Рабочее решение использовало .AsEnumerable() перед попыткой использовать мой пользовательский метод. Ты можешь!--2-->посмотри тут.


На самом деле, то, что вы передаете для подсчета, выглядит так:

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

но для этого потребуется EF, чтобы узнать, какой на самом деле метод IsMatch, что называется на этом существе, значит.

единственное, о чем я могу думать сейчас, это использовать какую-то динамическую обработку выражений для создания этого запроса dynamicaly. Или переработайте свой дизайн на что-то другое.

На самом деле, есть более простой и нормальный метод, который требует нескольких шагов чтобы сделать.

  1. сделать метод IsMatch статический.
  2. возвращение Expression<{your entity here}, bool> непосредственно с IsMatch.
  3. передайте это так:({your entity here}.IsMatch({parameters}))

отдых может оставаться таким же, как сейчас.

Edit: Example Это будет работать с конкретным объектом, поэтому я буду asume ваш объект ордер. Замените свою собственную сущность.

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));