C# 将具有左联接、组和求和的SQL转换为Linq查询

C# 将具有左联接、组和求和的SQL转换为Linq查询,c#,linq,C#,Linq,我试图在C&Linq中复制下面的SQL,但我对Linq的基本知识没有太多的经验 SELECT SUM(coalesce(cd.minutesspent,0)) FROM timelabels t LEFT JOIN challengedetails cd on cd.createddate = t.date GROUP BY t.date 这将为每个日期提供分钟总数,如果有空条目,则为零。我觉得很简单 // timelabels structure DateTime start = Da

我试图在C&Linq中复制下面的SQL,但我对Linq的基本知识没有太多的经验

SELECT SUM(coalesce(cd.minutesspent,0))
FROM timelabels t
LEFT JOIN challengedetails cd on cd.createddate = t.date 
GROUP BY t.date 
这将为每个日期提供分钟总数,如果有空条目,则为零。我觉得很简单

// timelabels structure 
DateTime start = DateTime.Now.AddDays(-14);
DateTime end = DateTime.Now;
List<DateTime> timelabels =  new List<DateTime>();
for (var dt = start; dt <= end; dt = dt.AddDays(1))
{
    timelabels.Add(dt);
}

// ChallengeDetails structure & sample data
class ChallengeDetails(){
    DateTime? Createddate
    int? MinutesSpent 
}
List<ChallengeDetails> ChallengeDetails = new List<ChallengeDetails >();
  List<ChallengeDetails> ChallengeDetails = new List<ChallengeDetails>();
            ChallengeDetails.Add(new ChallengeDetails { MinutesSpent = 44, Createddate = DateTime.Now.AddDays(-10) });
            ChallengeDetails.Add(new ChallengeDetails { MinutesSpent = 31, Createddate = DateTime.Now.AddDays(-7) });
            ChallengeDetails.Add(new ChallengeDetails { MinutesSpent = 13, Createddate = DateTime.Now.AddDays(-3) });
            ChallengeDetails.Add(new ChallengeDetails { MinutesSpent = 77, Createddate = DateTime.Now.AddDays(-2) });


// The Actual Code 
List<string> timedata = (from a in timelabels
                         join al in ChallengeDetails on a equals al.Createddate into All
                         from al in All.DefaultIfEmpty()
                         group al by a into grouped
                         select grouped.Sum(m => m.MinutesSpent ?? 0).ToString()
                        ).ToList();
看看这个,它应该可以工作-我有DefaultIfEmpty,它应该复制左连接。在我的总数之内??0'应该是任何没有ChallengeDetail的日期的回退

但我得到System.NullReferenceException:“对象引用未设置为对象的实例。”
m为空。我不应该得到这个,因为我已经覆盖了空条目,或者我完全弄错了吗?

在“实际代码”部分下,只需在求和函数中添加一个括号,如下所示 它应该注意null,甚至在Sum工作之前

select grouped.Sum(m => (m.MinutesSpent ?? 0)).ToString()

在“实际代码”部分下,只需在Sum函数中添加一个括号,如下所示 它应该注意null,甚至在Sum工作之前

select grouped.Sum(m => (m.MinutesSpent ?? 0)).ToString()

使用LINQ-Lambda表达式,您可以这样做:

var TotalMinutesSpentGroupedList = timelabels
         .GroupJoin(challengedetails,
                    t => date,
                    cd => createddate,
                    (t,cd) => new 
                    { 
                       MinutesSpent = cd.minutesspent ?? 0,
                       CreateDate = cd.createddate ?? DateTime.Now
                    })
         .SelectMany(tcd=> challengedetails.DefaultIfEmpty(),
                     (t, cd) => new 
                     { 
                        MinutesSpent = cd.minutesspent ?? 0,
                        CreateDate = cd.createddate ?? DateTime.Now
                     })
         .Select(s => new 
                     { 
                        MinutesSpent = cd.minutesspent ?? 0,
                        CreateDate = cd.createddate ?? DateTime.Now
                     })
         .GroupBy(g => g.createddate).Select(item => item.Sum(s => s.minutesspent));

使用LINQ-Lambda表达式,您可以这样做:

var TotalMinutesSpentGroupedList = timelabels
         .GroupJoin(challengedetails,
                    t => date,
                    cd => createddate,
                    (t,cd) => new 
                    { 
                       MinutesSpent = cd.minutesspent ?? 0,
                       CreateDate = cd.createddate ?? DateTime.Now
                    })
         .SelectMany(tcd=> challengedetails.DefaultIfEmpty(),
                     (t, cd) => new 
                     { 
                        MinutesSpent = cd.minutesspent ?? 0,
                        CreateDate = cd.createddate ?? DateTime.Now
                     })
         .Select(s => new 
                     { 
                        MinutesSpent = cd.minutesspent ?? 0,
                        CreateDate = cd.createddate ?? DateTime.Now
                     })
         .GroupBy(g => g.createddate).Select(item => item.Sum(s => s.minutesspent));

首先,对正在使用的数据层执行此操作哪个?。LINQ to对象与LINQ to SQL提供程序不同。第二件可能适用的事情:使用导航属性,而不是连接。这样做ORM将1。取消空引用,因为它是SQL和2。找出左连接本身。尝试以下操作:选择grouped.Summ=>m==null?0:m.MinutesSpent.ToStringPerhaps我可能会帮助你。您使用的LINQ是:LINQ到SQL/EF 6.x/EF Core 2.0/2.1/3.x/5.x/6.x?哪一个数据库提供程序?有时al在来自DefaultIfEmpty的对象的LINQ中为null,在这种情况下,m为null,m.MinutesPent为NullReferenceException。你需要m?分钟的时间吗??0表示LINQ到对象。这与数据库的LINQ不同。@NetMage关于m为null的说法是正确的-`m?.MinutesSpent??0`处理它。您的SQL-to-LINQ配方也正是我想要的!首先,对正在使用的数据层执行此操作哪个?。LINQ to对象与LINQ to SQL提供程序不同。第二件可能适用的事情:使用导航属性,而不是连接。这样做ORM将1。取消空引用,因为它是SQL和2。找出左连接本身。尝试以下操作:选择grouped.Summ=>m==null?0:m.MinutesSpent.ToStringPerhaps我可能会帮助你。您使用的LINQ是:LINQ到SQL/EF 6.x/EF Core 2.0/2.1/3.x/5.x/6.x?哪一个数据库提供程序?有时al在来自DefaultIfEmpty的对象的LINQ中为null,在这种情况下,m为null,m.MinutesPent为NullReferenceException。你需要m?分钟的时间吗??0表示LINQ到对象。这与数据库的LINQ不同。@NetMage关于m为null的说法是正确的-`m?.MinutesSpent??0`处理它。您的SQL-to-LINQ配方也正是我想要的!