繁体   English   中英

将两种扩展方法合而为一

[英]Combining two extension methods into one

我有这个扩展方法:

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

我讨厌两次拥有几乎相同的代码的想法,如何将这两种方法合而为一? (如果可能的话),或者至少使其成为两种方法,但其中一种进行过滤? 原始代码更长,这也是原因之一。

您可以直接和明确地在Employee上实现IFilterByEmployee

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

通过显式实现接口,它实际上使它成为一种“达到目的”的解决方案。

编辑:这可能不适用于LinqToEf。 直接编写SQL存在相同的问题。 查询的上下文在这里很关键,因此很难以LinqToEf可以智能(或神奇地)正确地解释它的方式来抽象查询。

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 e => e.Employee

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM