Тип узла выражения LINQ 'Invoke' не поддерживается в LINQ to Entities - PullRequest
2 голосов
/ 28 февраля 2011
public CategoryViewModel GetSingle( Expression<Func<CategoryViewModel, bool>> where)
        {
            Expression<Func<DAL.EntityModels.Category, CategoryViewModel>> converter =
                c => ToBll(c);

            var param = Expression.Parameter(typeof(DAL.EntityModels.Category), "category");
            var body = Expression.Invoke(where, Expression.Invoke(converter, param));
            var lambda = Expression.Lambda<Func<DAL.EntityModels.Category, bool>>(body, param);

            return  (CategoryViewModel )_categoryRepository.GetSingle(lambda);
}

Код _categoryRepository.GetSingle (lambda) вызывает исключение: «Тип узла выражения LINQ 'Invoke' не поддерживается в LINQ to Entities"

Есть ли простой способ избежать этого исключения? Я не хочу использовать другие инструменты, такие как LinqKit или PredicateBuilder.

1 Ответ

6 голосов
/ 01 марта 2011

Это касается некоторых деталей, лежащих в основе Linq2Entities, и различия между Linq2Objects и Linq2AnythingElse ...

Вы, очевидно, хорошо понимаете деревья выражений и генерируете их программно. Linq2Entities берет это дерево выражений и пытается преобразовать его в запрос SQL для запуска на сервере базы данных. Однако он не может отобразить произвольный код C # на его эквивалент в SQL (например, вызов toBll не имеет абсолютно никакого значения в SQL).

Другими словами, вы столкнулись с этой проблемой, потому что Linq2Entities пытается отобразить ваш вызов toBll в SQL, и с треском проваливается, потому что нет такого эквивалента. В том, что вы пытаетесь сделать, есть некоторый недостаток дизайна. Я предполагаю, что вы пытаетесь получить произвольное условие, выраженное в «где» для запуска на сервере базы данных. Однако ваше произвольное условие относится к объектам вашего бизнес-уровня, и ни SQL-сервер, ни структура сущностей ничего не знают об этих объектах.

То, что вам действительно нужно сделать для такого рода дизайна, - это иметь произвольное условие, выраженное в терминах типов Linq2Entities, а не типов BLL. Поскольку Linq2Entities знает об этих типах, он сможет преобразовать произвольное выражение в SQL (поскольку он имеет сопоставления для типов Linq2Entities с их эквивалентами SQL).

То, что я описал выше, действительно является правильным способом сделать это, в качестве альтернативы, вы можете перечислить запрос (который будет выполнен) и затем выполнить условия для возвращенного набора результатов. Поскольку в этот момент вы работаете в Linq2Objects (это просто стандартный код .NET, работающий с объектами в памяти), ваши функции будут работать без проблем. Однако это означает, что ваше предложение where будет выполняться в памяти, а НЕ на сервере базы данных, поэтому я бы не рекомендовал это

РЕДАКТИРОВАТЬ: OP запрошенный код ...

Чтобы это работало правильно, вам нужно изменить метод GetSingle, чтобы он принимал условие выражения, которое действует на тип EntityFramework, а не на ваш тип BLL. Затем вы можете удалить свое предложение конвертера из дерева выражений, и вы должны начать работу:

public CategoryViewModel GetSingle( Expression<Func<DAL.EntityModels.Category, bool>> where)
{

            var param = Expression.Parameter(typeof(DAL.EntityModels.Category), "category");
            var body = Expression.Invoke(where, param);
            var lambda = Expression.Lambda<Func<DAL.EntityModels.Category, bool>>(body, param);

            return  ToBLL((DAL.EntityModels.Category)_categoryRepository.GetSingle(lambda));
}

Проблема этого подхода заключается в том, что ваше выражение должно соответствовать типу EntityFramework, что может нарушить ваше желание скрыть детали абстрактного слоя данных. На этом этапе это довольно тяжелое везение, EntityFramework + BLL + Dynamic Query Generation = трудно получить право

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...