簡體   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