将EF LINQ方法语法转换为查询语法

5

如何使用LINQ查询语法编写完全相同的查询?

var q2 = list.GroupBy(x => x.GroupId)
             .Select(g => g
                 .OrderByDescending(x => x.Date)
                 .FirstOrDefault());

我认为这应该有效,但实际上并没有:
var q1 = from x in list
         group x by x.GroupId into g
         from y in g
         orderby y.Date descending
         select g.FirstOrDefault();

如果您想尝试一下,请使用以下测试程序:

public class MyClass
{
    public int Id { get; set; }
    public string GroupId { get; set; }
    public DateTime Date { get; set; }

    public override bool Equals(object obj)
    {
        var item = obj as MyClass;
        return item == null ? false : item.Id == this.Id;
    }
}

static void Main(string[] args)
{
    var list = new List<MyClass> 
    {
        new MyClass { GroupId = "100", Date=DateTime.Parse("01/01/2000"), Id = 1},
        new MyClass { GroupId = "100", Date=DateTime.Parse("02/01/2000"), Id = 2},
        new MyClass { GroupId = "200", Date=DateTime.Parse("01/01/2000"), Id = 3},
        new MyClass { GroupId = "200", Date=DateTime.Parse("02/01/2000"), Id = 4},
        new MyClass { GroupId = "300", Date=DateTime.Parse("01/01/2000"), Id = 5},
        new MyClass { GroupId = "300", Date=DateTime.Parse("02/01/2000"), Id = 6},
    };

    var q1 = from x in list
                group x by x.GroupId into g
                from y in g
                orderby y.Date descending
                select g.FirstOrDefault();

    var q2 = list.GroupBy(x => x.GroupId)
                    .Select(g => g
                        .OrderByDescending(x => x.Date)
                        .FirstOrDefault());

    Debug.Assert(q1.SequenceEqual(q2));
}

你尝试过使用 let 运算符吗? - frenchie
@frenchie 不,我没有。 - Eren Ersönmez
2个回答

3

在理解查询语法中没有FirstOrDefault操作符(如果项目已分组,则组中至少有一个项目,因此需要First),但其他内容的翻译方式如下:

var q1 = from c in list
         orderby c.Date descending
         group c by c.GroupId into g
         select g.First();

技巧在于,如果您对有序序列进行分组,则组中的项目将被排序。 然后就可以:

q1.SequenceEqual(q2) 返回true

顺便说一句,根据LINQ Pad的说法,此查询生成的完全相同的SQL与具有嵌套from x in g orderby x.Date descending select x的查询相同。

更新 还有我的错误- First 将使用LINQ to Objects或LINQ to SQL,但是对于LINQ to Entities,您应该使用FirstOrDefault。第二个注意事项-这些查询(我的和嵌套查询的)将为LINQ to SQL生成相同的SQL,但是对于EF,我的排序不适用。


+1。这确实会产生相同的结果(并且可能更有效率),不过我很好奇知道确切的函数等效,而这并不是。 - Eren Ersönmez
@ErenErsönmez 我也很好奇,因此用 LINQ Pad 验证了这两个查询 :) - Sergey Berezovskiy
问题实际上是关于 LINQ to Objects 的。但我也在使用 SQL Profiler 查看 Entity Framework 执行的 SQL,并且看起来 EF 绕过了 orderby(在执行的 SQL 中没有 ORDER BY) -- 因此添加 descending 或不添加都没有区别。 - Eren Ersönmez
@ErenErsönmez 是的,这就是我在最近更新中谈到的内容。 - Sergey Berezovskiy

3

反射器给了我以下内容:

var q2 = from x in list
         group x by x.GroupId into g
         select (
             from x in g
             orderby x.Date descending
             select x).FirstOrDefault();

这看起来大致正确。

正如Lazy所说,不需要使用FirstOrDefault替换First,因为组不会为空,但这样做也不会有害。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接