Combining two extension methods into one

I have this extension method:

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; } 

and another that is exactly the same, but it directly filters the Employees context:

 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; } 

I hate the idea of โ€‹โ€‹having almost the same code twice, how can I combine these two methods into one? (if possible) or at least do it in two ways, but filtering in one of them? the source code is much longer, which is also one of the reasons.

+6
source share
2 answers

You can implement IFilterByEmployee on Employee directly and explicitly:

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

By explicitly implementing the interface, it essentially makes it a "solution."

EDIT: This is unlikely to work with LinqToEf. You have the same problem with writing SQL directly. The context of the query is critical, so itโ€™s very difficult to abstract it so that LinqToEf can intelligently (or magically) interpret it correctly.

+1
source

This is possible with 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(); creates a wrapper around the EF request, which ensures that employeeSelector.Compile().Invoke(e) will be translated accordingly and will not, despite the way it looks, will actually compile any expression tree, and EF should only see expressions, which he actually supports.

You can use e => e as an employee selector if you filter your employees directly, or e => e.Employee if you do not.

+1
source

All Articles