我有这种扩展方法:
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;
}
我讨厌两次使用几乎相同的代码的想法,如何将这两种方法合二为一? (如果可能的话)或者至少使它成为两种方法,但在其中一种方法中进行过滤?原始代码要长得多,这也是其中一个原因。
答案 0 :(得分:1)
您可以直接明确地在IFilterByEmployee
上实施Employee
:
public class Employee : IFilterByEmployee
{
Employee IFilterByEmployee.Employee
{
get { return this; }
}
}
通过明确地实现接口,它实质上使它成为“达到目的的一种解决方案”。
编辑:这可能不适用于LinqToEf。直接编写SQL会遇到同样的问题。查询的上下文在这里是至关重要的,因此很难以LinqToEf可以智能地(或神奇地)正确地解释它的方式来抽象它。
答案 1 :(得分: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
。