#c# #.net #entity-framework #linq-to-entities #where-clause
#c# #.net #entity-framework #linq-to-entities #where-предложение
Вопрос:
Я пытаюсь создать динамический скомпилированный предикат и использовать его для запроса Entity Framework ObjectSet. Выполняется следующий код и возвращается правильный результат, но оператор SQL SELECT генерируется без предложения WHERE:
var db = new DBHelper();
ParameterExpression entity = Expression.Parameter(typeof(HighSchoolServicesDataAccess.Faculty), "entity");
var filterentity = Expression.Lambda(Expression.Equal(Expression.Property(entity, "HighSchoolID"), Expression.Constant(90, typeof(int))), entity);
Func<HighSchoolServicesDataAccess.Faculty, bool> predicate = (Func<HighSchoolServicesDataAccess.Faculty, bool>)filterentity.Compile();
var res = db.DBContext.Faculties.Where(predicate);
dataGridView2.DataSource = res.ToList();
Сгенерированный оператор SQL является:
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[HighSchoolID] AS [HighSchoolID],
[Extent1].[TypeID] AS [TypeID],
[Extent1].[Name] AS [Name]
FROM [dbo].[Faculties] AS [Extent1]
и когда я использую явное выражение типа
var res = db.DBContext.Faculties.Where(f => f.HighSchoolID == 90);
генерируется правильный SQL.
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[HighSchoolID] AS [HighSchoolID],
[Extent1].[TypeID] AS [TypeID],
[Extent1].[Name] AS [Name]
FROM [dbo].[Faculties] AS [Extent1]
WHERE 90 = [Extent1].[HighSchoolID]
Как я могу заставить EF создать предложение WHERE в SQL?
Ответ №1:
Не уверен, но может быть, вы устанавливаете predicate
значение compiled Func<...>
и не сохраняете его как Expression<Func<...>>
, поэтому он преобразуется в IL, прежде чем EF сможет его обработать? Вы пробовали, например
var predicate =
(Expression<Func<HighSchoolServicesDataAccess.Faculty, bool>>)filterentity;
?
Ответ №2:
Вы создали предикат, но в конце вы его скомпилировали, что означает, что он больше не является выражением, и как только вы передаете его в Where, вы используете linq-to-objects вместо linq-to-entities. Это означает, что все записи передаются в приложение, а фильтрация выполняется в памяти.
Попробуйте это вместо:
var res=db.DBContext.Faculties.Where(filterentity);
dataGridView2.DataSource = res.ToList();
Комментарии:
1. Я не согласен, плохо загружать все и применять фильтрацию в памяти, это все равно будет делать то же самое. Это не приведет к созданию другого SQL, он все равно будет генерировать тот же SQL.
Ответ №3:
Linq требуется выражение функции, а не скомпилированная функция. Пожалуйста, используйте reflector, чтобы увидеть, что генерируется компилятором для вашего выражения linq.
Дерево выражений Enire должно быть доступно для предложения Linq where без компиляции.
var db = new DBHelper();
ParameterExpression entity =
Expression.Parameter(typeof(HighSchoolServicesDataAccess.Faculty),
"entity");
Expression<Func<HighSchoolServicesDataAccess.Faculty, bool>> filterentity =
Expression.Lambda<Func<HighSchoolServicesDataAccess.Faculty, bool>>(
Expression.Equal(
Expression.Property(entity, "HighSchoolID"),
Expression.Constant(90, typeof(int))), entity);
// not at all needed...
//Func<HighSchoolServicesDataAccess.Faculty, bool> predicate =
// (Func<HighSchoolServicesDataAccess.Faculty, bool>)filterentity.Compile();
var res = db.DBContext.Faculties.Where(filterentity);
dataGridView2.DataSource = res.ToList();