C# 将linq查询转换为lambda语法

C# 将linq查询转换为lambda语法,c#,linq,lambda,C#,Linq,Lambda,我想在按天和小时发送消息时显示热图,并编写了一些linq查询 原始SQL查询 SELECT weekday, hr , count(message.hour) FROM (SELECT days.dow as weekday, hours.hour as hr from days left join hours,message on message.dow = days.dow group by days.dow, hours.hour) LEFT JOIN message on message

我想在按天和小时发送消息时显示热图,并编写了一些linq查询

原始SQL查询

SELECT weekday, hr , count(message.hour)
FROM (SELECT days.dow as weekday, hours.hour as hr from days left join hours,message on message.dow = days.dow group by days.dow, hours.hour)
LEFT JOIN message on message.dow = weekday and message.hour = hr group by weekday, hr
消息类

public class Message
{
    public long Id { get; set; }
    public string Text { get; set; }
    public DateTime Timestamp { get; set; }
}
林克奎里特工厂

int[] Hours = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 };
int[] Days = { 0, 1, 2, 3, 4, 5, 6 };
List<Message> messages = new List<Message>();
/*
  Load Message data from csv file
  ...
*/
var heatmap = from d in
                  (from message in Messages
                  join h in Hours on message.Timestamp.Hour equals h
                  join d in Days on (int)message.Timestamp.DayOfWeek equals d
                  orderby d, h
                  group new { d, h } by new { d, h } into g
                  select new { Weekday = g.Key.d, Hour = g.Key.h })
              join message in Messages on new { d.Weekday, d.Hour } equals new { Weekday = (int)message.Timestamp.DayOfWeek, Hour = message.Timestamp.Hour }
              group new { d.Weekday, d.Hour } by new { d.Weekday, d.Hour } into g
              select new { Weekday = g.Key.Weekday, Hour = g.Key.Hour, Total = g.Count() };
下面是我将LINQ查询转换为lambda语法代码的代码,但它不起作用!:

int[] Hours = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 };
int[] Days = { 0, 1, 2, 3, 4, 5, 6 };
List<Message> messages = new List<Message>();
/*
  Load Message data from csv file
  ...
*/
var heatmapLambda = (Messages.Join(Hours, message => message.Timestamp.Hour, h => h, (m, h) => new { m, h })
                                  .Join(Days, m => (int)m.m.Timestamp.DayOfWeek, d => d, (m,d) => new { m, d })
                                  .OrderBy(m => new {m.d, m.m.h})
                                  .GroupBy(g => new {g.d, g.m.h})
                                  .Select(r => new {
                                      Weekday = r.Key.d,
                                      Hour = r.Key.h
                                  }))
                              .Join(Messages, d => new {d.Weekday, d.Hour}, m => new { Weekday = (int)m.Timestamp.DayOfWeek, Hour = m.Timestamp.Hour}, (d,h) => new { d.Weekday, d.Hour})
                              .GroupBy(g => new { g.Weekday, g.Hour})
                              .Select(r => new { Weekday = r.Key.Weekday, Hour = r.Key.Hour, Count = r.Count() });

Heatmap Lambda没有任何项目。什么是我的linq查询的正确lambda表达式?

在我看来,您正在进行许多不必要的连接

当您这样做时:

from message in Messages
join h in Hours on message.Timestamp.Hour equals h
join d in Days on (int)message.Timestamp.DayOfWeek equals d
join message in Messages on new { d.Weekday, d.Hour } equals new { Weekday = (int)message.Timestamp.DayOfWeek, Hour = message.Timestamp.Hour }
…这与:

    from message in Messages
    let h = message.Timestamp.Hour
    let d = (int)message.Timestamp.DayOfWeek
当你这样做的时候:

from message in Messages
join h in Hours on message.Timestamp.Hour equals h
join d in Days on (int)message.Timestamp.DayOfWeek equals d
join message in Messages on new { d.Weekday, d.Hour } equals new { Weekday = (int)message.Timestamp.DayOfWeek, Hour = message.Timestamp.Hour }
…你基本上是在重新加入你原来的信息

我认为这是一个等价的问题:

var heatmap =
    from message in Messages
    let Hour = message.Timestamp.Hour
    let Weekday = (int)message.Timestamp.DayOfWeek
    orderby Weekday, Hour
    group message by new { Weekday, Hour } into gms
    select new { gms.Key.Weekday, gms.Key.Hour, Count = gms.Count() };
…因此,如果是这样,那么这就是使用lambdas所需要的:

var heatmap =
    Messages
        .OrderBy(message => (int)message.Timestamp.DayOfWeek)
        .ThenBy(message => message.Timestamp.Hour)
        .GroupBy(message => new { Weekday = (int)message.Timestamp.DayOfWeek, message.Timestamp.Hour })
        .Select(gms => new { gms.Key.Weekday, gms.Key.Hour, Count = gms.Count() });

在我看来,查询的主要目标应该是以最佳方式获得正确的结果,而不是查询、方法或混合使用的语法

在您的情况下,查询远远不是最优的-不必要的连接、分组和排序。据我所见,您正试图从Days和Hours集合中获得每个工作日的邮件数,小时组合,这可以通过简单的笛卡尔积结合如下方法实现

var query = 
    from key in (from d in Days from h in Hours select new { Weekday = d, Hour = h })
    join m in Messages
    on key equals new { Weekday = (int)m.Timstamp.DayOfWeek, m.Timestamp.Hour } into items
    select new { key.Weekday, key.Hour, Total = items.Count() };
通常,在处理联接和/或分组时,由于标识符透明,使用查询语法更容易、更自然。在这种特殊情况下,方法语法没有太大区别,但您需要知道如何映射结构:

var query = 
    Days.SelectMany(d => Hours, (d, h) => new { Weekday = d, Hour = h })
    .GroupJoin(Messages, 
        key => key, m => new { Weekday = (int)m.Timstamp.DayOfWeek, m.Timestamp.Hour },
        (key, items) => new { key.Weekday, key.Hour, Total = items.Count() });

你能解释一下你想通过这个查询实现什么吗。还有一个消息的示例集合也会很有帮助。@MaximFleitling我在lambda中添加了消息类实现和结果热图数据集合,难道不应该有foreach吗?与消息中的foreachmessage类似,连接使用linq语法更有效。然后,可以在连接周围放一个括号,并使用lambda表达式。所以它应该是这样的:从d。。。lambda expression.GroupBylinq expressions…@Mystika-LINQ查询和lambda语法实际上没有区别。显然,它们看起来不同,但编译器会尽一切努力将查询语法转换为lambda语法,然后进行编译。所以根本没有语义上的区别。长话短说:OrderBym=>new{m.d,m.m.h}抛出了一个exeption,必须实现IComparable,而OrderBym=>m.d.ThenBym=>m.m.h之所以有效,是因为整数是可比的。@grek40-这很好,但这与我的答案有什么关系?对不起,我的评论有点误导。基本上,您给出了一些关于如何优化查询的有价值的建议,并且在此过程中,您还解决了原始查询的特定阻塞问题。我认为在回答这个问题时,强调最小解决方案是很重要的,这样其他人就可以理解哪些部分是绝对必要的,哪些部分是建议的优化,在这种情况下也是非常重要的