2014-02-02 3 views
6

У меня есть этот метод расширения:Объединяя два метода расширения в один

public static IQueryable<T> FilterByEmployee<T>(this IQueryable<T> source, EmployeeFilter filter) 
    where T : class, IFilterableByEmployee 
    { 
     if (!string.IsNullOrEmpty(filter.Gender)) 
      source = source.Where(e => e.Employee.Gender == filter.Gender); 

     if (!string.IsNullOrEmpty(filter.NationalityID)) 
      source = source.Where(e => e.Employee.NationalityID == filter.NationalityID); 

     // filter the group 
     if (filter.IncludeChildGroups) 
     { 
      var groups = Security.GetAllChildGroups(filter.GroupID); 
      source = source.Where(e => e.Employee.EmployeeGroupID.HasValue 
       && groups.Contains(e.Employee.EmployeeGroupID.Value)); 
     } 
     else 
     { 
      source = source.Where(e => e.Employee.EmployeeGroupID == filter.GroupID); 
     } 

     // filter status 
     if (filter.OnlyActiveEmployees) 
      source = source.Where(e => e.Employee.Status == "Active"); 

     return source; 
    } 

и еще один, который является точно такой же, но он фильтрует Employees контекст непосредственно:

public static IQueryable<T> Filter<T>(this IQueryable<T> source, EmployeeFilter filter) 
    where T : Employee 
    { 
     if (!string.IsNullOrEmpty(filter.Gender)) 
      source = source.Where(e => e.Gender == filter.Gender); 

     if (!string.IsNullOrEmpty(filter.NationalityID)) 
      source = source.Where(e => e.NationalityID == filter.NationalityID); 

     // filter the group 
     if (filter.IncludeChildGroups) 
     { 
      var groups = Security.GetAllChildGroups(filter.GroupID); 
      source = source.Where(e => e.EmployeeGroupID.HasValue 
       && groups.Contains(e.EmployeeGroupID.Value)); 
     } 
     else 
     { 
      source = source.Where(e => e.EmployeeGroupID == filter.GroupID); 
     } 

     // filter status 
     if (filter.OnlyActiveEmployees) 
      source = source.Where(e => e.Status == "Active"); 

     return source; 
    } 

Я ненавижу идея иметь почти тот же код дважды, как я могу объединить эти два метода в один? (если возможно) или, по крайней мере, сделать это двумя способами, но фильтрация в одном из них? исходный код намного длиннее, что также является одной из причин.

ответ

1

Вы могли бы реализовать IFilterByEmployee на Employee прямо и недвусмысленно:

public class Employee : IFilterByEmployee 
{ 
    Employee IFilterByEmployee.Employee 
    { 
     get { return this; } 
    } 
} 

При реализации интерфейса в явном виде, по существу, делает это означает для конечного 'вида раствора.

EDIT: Это вряд ли будет работать с LinqToEf. У вас такая же проблема с написанием SQL напрямую. Контекст запроса имеет решающее значение, поэтому очень сложно абстрагировать его так, чтобы LinqToEf мог разумно (или волшебно) интерпретировать его правильно.

+0

Я собирался прокомментировать, что он не работает, но вы уже обновили ответ :) спасибо в любом случае. –

1

Это должно быть возможным с LINQKit:

public static IQueryable<T> Filter<T>(this IQueryable<T> source, Expression<Func<T, Employee>> employeeSelector, EmployeeFilter filter) 
{ 
    source = source.AsExpandable(); 

    if (!string.IsNullOrEmpty(filter.Gender)) 
     source = source.Where(e => employeeSelector.Compile().Invoke(e).Gender == filter.Gender); 

    if (!string.IsNullOrEmpty(filter.NationalityID)) 
     source = source.Where(e => employeeSelector.Compile().Invoke(e).NationalityID == filter.NationalityID); 

    // filter the group 
    if (filter.IncludeChildGroups) 
    { 
     var groups = Security.GetAllChildGroups(filter.GroupID); 
     source = source.Where(e => employeeSelector.Compile().Invoke(e).EmployeeGroupID.HasValue 
      && groups.Contains(employeeSelector.Compile().Invoke(e).EmployeeGroupID.Value)); 
    } 
    else 
    { 
     source = source.Where(e => employeeSelector.Compile().Invoke(e).EmployeeGroupID == filter.GroupID); 
    } 

    // filter status 
    if (filter.OnlyActiveEmployees) 
     source = source.Where(e => employeeSelector.Compile().Invoke(e).Status == "Active"); 

    return source; 
} 

source = source.AsExpandable(); создает оболочку вокруг запроса EF, который гарантирует, что employeeSelector.Compile().Invoke(e) переводится соответствующим образом и не происходит, несмотря на, как он выглядит, на самом деле компиляции любого дерева выражений, и EF должен видеть только выражения, которые он фактически поддерживает.

Вы можете использовать e => e в качестве селектора, если вы фильтруете непосредственно сотрудников, или e => e.Employee, если вы этого не сделаете.

Смежные вопросы