【问题标题】:Combining two extension methods into one将两种扩展方法合二为一
【发布时间】:2014-02-02 07:19:34
【问题描述】:

我有这个扩展方法:

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

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

【问题讨论】:

    标签: c# entity-framework linq-to-entities extension-methods


    【解决方案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 =&gt; e 作为员工选择器,如果不过滤,则可以使用 e =&gt; e.Employee

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • 我要评论说它不起作用,但你已经更新了答案:) 无论如何谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 2017-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-29
      • 1970-01-01
      相关资源
      最近更新 更多