简体   繁体   English

如何使此LINQ查询更整洁?

[英]How can I make this LINQ query cleaner?

I have recently written a LINQ query to get a Dictionary containing the last 6 month's placement amounts. 我最近写了一个LINQ查询来获取包含最近6个月的刊登位置数量的Dictionary

It is returning a Dictionary of Month string - Decimal Amount pairs. 它返回一个月Dictionary字符串-小数对。

It seems kind of cludgey. 似乎有点笨拙。 Any of you LINQ masters out there able to help me refactor this to make a bit cleaner? 你们中的LINQ大师中有谁能够帮助我进行重构以使其更加整洁?

/// <summary>
/// Gets the last 6 months of Placement History totalled by Month 
/// for all Agencies
/// </summary>
/// <returns></returns>
public Dictionary<string, decimal> getRecentPlacementHistory()
{
    var placementHistoryByMonth = new Dictionary<string, decimal>();

    using (DemoLinqDataContext db = new DemoLinqDataContext())
    {
        for (int i = 0; i < 6; i++)
        {
            Decimal monthTotal = 
              (from a in db.Accounts
               where 
                 (a.Date_Assigned.Value.Month == DateTime.Now.AddMonths(-i).Month &&
                  a.Date_Assigned.Value.Year == DateTime.Now.AddMonths(-i).Month)
               select a.Amount_Assigned).Sum();
            String currentMonth = DateTime.Now.AddMonths(-i).ToString("MMM");

            placementHistoryByMonth.Add(currentMonth, monthTotal);
        }
        return placementHistoryByMonth;
    }
}

First problem: 第一个问题:

where (a.Date_Assigned.Value.Month == DateTime.Now.AddMonths(-i).Month &&
       a.Date_Assigned.Value.Year == DateTime.Now.AddMonths(-i).Month)

Shouldn't the latter expression end with .Year rather than .Month? 后一个表达式不应该以.Year而不是.Mon结尾吗? Surely you'll rarely get a year with a value of 1-12... 当然,您很少会得到价值1-12的年份...

I would extract the idea of the "current month" as you're using it a lot. 由于您经常使用“当前月份”,因此我将其提取出来。 Note that you're also taking the current time multiple times, which could give odd results if it runs at midnight at the end of a month... 请注意,您还会多次使用当前时间,如果该时间在月底的午夜运行,则可能会产生奇怪的结果...

public Dictionary<string, decimal> getRecentPlacementHistory()
{
    var placementHistoryByMonth = new Dictionary<string, decimal>();
    using (DemoLinqDataContext db = new DemoLinqDataContext())
    {
        DateTime now = DateTime.Now;

        for (int i = 0; i < 6; i++)
        {
            DateTime selectedDate = now.AddMonths(-i);

            Decimal monthTotal = 
               (from a in db.Accounts
                where (a.Date_Assigned.Value.Month == selectedDate.Month &&
                       a.Date_Assigned.Value.Year == selectedDate.Year)
                select a.Amount_Assigned).Sum();

            placementHistoryByMonth.Add(selectedDate.ToString("MMM"),
                                        monthTotal);
        }
        return placementHistoryByMonth;
    }
}

I realise it's probably the loop that you were trying to get rid of. 我意识到这可能是您要摆脱的循环。 You could try working out the upper and lower bounds of the dates for the whole lot, then grouping by the year/month of a.Date_Assigned within the relevant bounds. 您可以尝试计算整个批次日期的上下限,然后在相关范围内按a.Date_Assigned的年/月分组。 It won't be much prettier though, to be honest. 老实说,这不会太漂亮。 Mind you, that would only be one query to the database, if you could pull it off. 请注意,如果可以进行查询,那只会是对数据库的一个查询。

Use Group By 使用分组依据

DateTime now = DateTime.Now;
DateTime thisMonth = new DateTime(now.Year, now.Month, 1);

Dictionary<string, decimal> dict;
using (DemoLinqDataContext db = new DemoLinqDataContext())
{
    var monthlyTotal = from a in db.Accounts
        where a.Date_Assigned > thisMonth.AddMonths(-6)
        group a by new {a.Date_Assigned.Year, a.Date_Assigned.Month} into g
        select new {Month = new DateTime(g.Key.Year, g.Key.Month, 1),
                    Total = g.Sum(a=>a.Amount_Assigned)};

    dict = monthlyTotal.OrderBy(p => p.Month).ToDictionary(n => n.Month.ToString("MMM"), n => n.Total);
}

No loop needed! 无需循环!

If you are not worried about missing months with no data,then I had a similar problem where I did the following : (translated to your variables) 如果您不担心缺少数据的月份,那么我在执行以下操作时也会遇到类似的问题:(转换为您的变量)

  DateTime startPeriod = 
     new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddMonths(-6);

  var query1 = from a in db.Accounts where a.Date_Assigned >= startPeriod
 group a by new { a.Date_Assigned.Year  ,a.Date_Assigned.Month  } into result
 select new
 {
     dt = new DateTime( result.Key.Year, result.Key.Month , 1),
     MonthTotal = result.Sum(i => i.Amount_Assigned)
 } ;             

  var dict = query1.OrderBy(p=> p.dt).ToDictionary(n => n.Dt.ToString("MMM") , n => n.MonthTotal );

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

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