Я хотел бы создать скомпилированный запрос, который использует предикаты многократного использования.Пример, чтобы прояснить это:
ObjectContext.Employees.Where(EmployeePredicates.CustomerPredicate)
EmployeePredicates - это статический класс со свойством CustomerPredicate, которое выглядит следующим образом:
public static Expression<Func<Employee, bool>> CustomerPredicate
{
get
{
return t => t.CustomerId == 1;
}
}
Это работает, как и ожидалось.Однако в большинстве случаев вы бы хотели передать параметр Expression.Чтобы достичь этого, я должен изменить свойство на статическую функцию:
public static Expression<Func<Employee, bool>> CustomerPredicate(int id)
{
return t => t.CustomerId == id;
}
И я могу использовать это так:
ObjectContext.Employees.Where(EmployeePredicates.CustomerPredicate(id))
Это работает, но теперь приходит сложная часть.Я хотел бы скомпилировать этот запрос ... Visual Studio не выдает никаких ошибок компиляции, но когда я запускаю этот пример, во время выполнения выдается следующее исключение:
Internal .NET Framework Data Provider error 1025
Просто так, чтобы мы былиздесь же приведен полный код, который дает мне исключение:
var _compiledQuery = CompiledQuery.Compile<AdventureWorksEntities, int, IQueryable<Employee>>(
(ctx, id) =>
(ctx.Employee.Where(EmployeePredicates.CustomerPredicate(id))
));
Кто-нибудь знает, почему выбрасывается это исключение?Я взял этот способ работы с http://www.albahari.com/nutshell/linqkit.aspx. Любая помощь будет высоко ценится.
Спасибо Джон,
Проблема с подходом, который вы описываете, заключается в том, чтосцепление предикатов вместе станет очень трудным.Что если мне нужно объединить этот предикат с другим предикатом, который фильтрует сотрудников с определенным именем?Затем вы получите множество вариантов выбора для передачи параметров.
(ctx, id, name) =>
(ctx.Employee.Select(emp => new {emp, id})
.Where(EmployeePredicates.CustomerPredicate(id))
.Select(emp => new {emp, name})
.Where(EmployeePredicates.NamePredicate(name))
Это становится еще хуже, когда вы работаете над объединенными таблицами.
(ctx, id, name) =>
(ctx.Employee
.Join(ctx.Contact, e=> e.ContactId, c => c.Id), (emp, cont) => new Container<Employee, Customer> {Employee = emp, Contact = cont})
.Where(EmployeePredicates.CustomerPredicate(id))
.Where(EmployeePredicates.NamePredicate(name))
.Select(t => new EmployeeDTO {Name = t.cont.Name, Customer = e.emp.Customer})
Потому что каждый Где () работает с чем-то типа T и возвращает что-то типа T, WherePredicates в приведенном выше коде должны работать с типом Container.Это делает очень трудным повторное использование Предикатов.И повторное использование было первоначальной целью этого подхода ...