Linq Join和GroupBy重构

时间:2015-10-02 09:01:54

标签: c# entity-framework linq

我认为我已经完成了一个非常重复的查询,我想知道你是否可以帮助我理解如何做得更好。我正在执行JoinGroupBy,具体取决于EnumDateFilter。你能帮帮我吗请尽快缩短代码吗?

非常感谢!

foreach (Client client in listClient){
    var books = _servBook.GetBooks(BeginDate, EndDate, ClientId).ToList();

    switch (enumDateFilter)
    {
        case EnumDateFilter.Today:
        case EnumDateFilter.OneDay:
            {
                books.Join(
                    dates,
                    bk => new { bk.Date.Hour, bk.Date.Day, bk.Date.Month, bk.Date.Year },
                    cd => new { cd.Date.Hour, cd.Date.Day, cd.Date.Month, cd.Date.Year },
                    (bk, chart) => new { bk, chart.Data }
                )
                .GroupBy(a => new
                {
                    a.bk.Date.Hour,
                    a.bk.Date.Day,
                    a.bk.Date.Month,
                    a.bk.Date.Year,
                    a.Data
                })
                .Select(
                    a =>
                    {
                        a.Key.Data[client.Name] = a.Count().ToString();
                        return a;
                    }
                ).ToList();
            }
            break;

        case EnumDateFilter.OneWeek:
        case EnumDateFilter.OneMonth:
        case EnumDateFilter.LastWeek:
        case EnumDateFilter.LastMonth:
            {
                books.Join(
                    dates,
                    bk => new { bk.Date.Day, bk.Date.Month, bk.Date.Year },
                    cd => new { cd.Date.Day, cd.Date.Month, cd.Date.Year },
                    (bk, chart) => new { bk, chart.Data }
                )
                .GroupBy(a => new
                {
                    a.bk.Date.Day,
                    a.bk.Date.Month,
                    a.bk.Date.Year,
                    a.Data
                })
                .Select(
                    a =>
                    {
                        a.Key.Data[client.Name] = a.Count().ToString();
                        return a;
                    }
                ).ToList();

                break;
            }

        case EnumDateFilter.ThreeMonths:
        case EnumDateFilter.SixMonths:
        case EnumDateFilter.OneYear:
        case EnumDateFilter.LastThreeMonths:
        case EnumDateFilter.LastSixMonths:
        case EnumDateFilter.LastYear:
            {
                books.Join(
                    dates,
                    bk => new { bk.Date.Month, bk.Date.Year },
                    cd => new { cd.Date.Month, cd.Date.Year },
                    (bk, chart) => new { bk, chart.Data }
                )
                .GroupBy(a => new
                {
                    a.bk.Date.Month,
                    a.bk.Date.Year,
                    a.Data
                })
                .Select(
                    a =>
                    {
                        a.Key.Data[client.Name] = a.Count().ToString();
                        return a;
                    }
                ).ToList();
                break;
            }

        case EnumDateFilter.SinceBeginning:
            {
                books.Join(
                    dates,
                    bk => new { bk.Date.Year },
                    cd => new { cd.Date.Year },
                    (bk, chart) => new { bk, chart.Data }
                )
                .GroupBy(a => new
                {
                    a.bk.Date.Year,
                    a.Data
                })
                .Select(
                    a =>
                    {
                        a.Key.Data[client.Name] = a.Count().ToString();
                        return a;
                    }
                ).ToList();
                break;
            }
    }

1 个答案:

答案 0 :(得分:0)

使用匿名类型,这很难实现。您可以尝试使用具体类型进行连接和分组。例如,您必须创建

struct TimeDescriptor{
   public int Year;
   //TODO: Put other fields
}

这将允许您分解一些lambda表达式,例如

Expression<Func<Book, TimeDescriptor>> bookSelector = b => new TimeDescriptor{Year = b.Date.Year, ...}
Expression<Func<DateType, TimeDescriptor>> dateSelector = d => new TimeDescriptor{Year = d.Date.Year}

然后可以在LINQ中使用,例如

books.Join(dates, bookSelector, dateSelector, ...)

然后可以将您的开关缩减为获得适当的选择器,并且可以在交换机外部编写主查询。例如:

Expression<Func<Book, TimeDescriptor>> bookSelector;
Expression<Func<DateType, TimeDescriptor>> dateSelector;

switch((enumDateFilter)
{
    case EnumDateFilter.Today:
    case EnumDateFilter.OneDay:
         bookSelector = ...;
         dateSelector = ...;
         break;
    ...
}

return books.Join(dates, bookSelector, dateSelector, ...)

我希望这可以帮助你获得一些想法。