Это касается некоторых деталей, лежащих в основе 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 = трудно получить право