LINQ与LINQ to Entities,在分组时保持排序

Ton*_*olf 9 c# linq entity-framework

这是正常的LINQ,并且此测试成功:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;

namespace TestLINQ.Tests
{
[TestClass]
public class UnitTest2
{

    [TestMethod]
    public void TestGroupingAndOrdering()
    {
        var persons = GetTestPersons();

        //Try get oldest Man and oldest Woman.
        var Oldest = persons
            .Where(p => p.Sex == TestGender.Male || p.Sex == TestGender.Female)
            .OrderBy(p => p.DateOfBirth)
            .GroupBy(p => p.Sex)
            .Select(g => g.First());

        //Try get youngest Man and youngest Woman. 
        var youngest = persons
            .Where(p => p.Sex == TestGender.Male || p.Sex == TestGender.Female)
            .OrderByDescending(p => p.DateOfBirth) //reversed sorting.
            .GroupBy(p => p.Sex)
            .Select(g => g.First());                

        Assert.AreEqual(Oldest.ToList().Count, 2);
        Assert.AreEqual(youngest.ToList().Count, 2);

        Assert.AreEqual(Oldest.First().Name, "Navya"); //Oldest Woman
        Assert.AreEqual(Oldest.Last().Name, "Pranav"); //Oldest Man (Note: last() gets the second grouping)

        Assert.AreEqual(youngest.First().Name, "Aditya"); // Youngest Man.
        Assert.AreEqual(youngest.Last().Name, "Ananya"); // Youngest Woman.
    }

    public class TestPerson
    {
        public string Name { get; set; }
        public DateTime DateOfBirth { get; set; }
        public TestGender Sex { get; set; }

        public TestPerson(string name, DateTime dob, TestGender sex)
        {
            Name = name;
            DateOfBirth = dob;
            Sex = sex;
        }
    }

    public enum TestGender
    {
        Male,
        Female,
        Unknown
    }

    private List<TestPerson> GetTestPersons()
    {
        var list = new List<TestPerson>();
        //LOL @ using indian names.
        list.Add(new TestPerson("Advik", new DateTime(625909337000000000), TestGender.Male));
        list.Add(new TestPerson("Navya", new DateTime(608385600000000000), TestGender.Female));
        list.Add(new TestPerson("Ananya", new DateTime(626631005000000000), TestGender.Female));
        list.Add(new TestPerson("Aditya", new DateTime(630061565000000000), TestGender.Male));
        list.Add(new TestPerson("Veer", new DateTime(614074365000000000), TestGender.Male));
        list.Add(new TestPerson("Ishaan", new DateTime(617700836000000000), TestGender.Male));
        list.Add(new TestPerson("Pranav", new DateTime(610170773000000000), TestGender.Male));
        list.Add(new TestPerson("Purusha", new DateTime(629134727000000000), TestGender.Unknown));
        list.Add(new TestPerson("Avani", new DateTime(624015444000000000), TestGender.Female));
        list.Add(new TestPerson("Pari", new DateTime(625879085000000000), TestGender.Female));
        list.Add(new TestPerson("Nirguna", new DateTime(630489769000000000), TestGender.Unknown));
        return list;
    }
}
}
Run Code Online (Sandbox Code Playgroud)

但是当您将数据插入数据库并尝试在使用LINQ to Entities时执行相同操作时,无论您应用哪种排序,似乎结果SQL都是相同的.

    [TestMethod]
    public void TestGroupingAndOrdering()
    {
        using (var context = new TestCRM())
        {
            var persons = context.Persons;

            var result = persons
                .Where(p => p.Sex == Gender.Male || p.Sex == Gender.Female)
                .OrderBy(p => p.DateOfBirth)  // REGARDLESS of what you do here, the resulting SQL is the same.
                .GroupBy(p => p.Sex)
                .Select(g => g.FirstOrDefault());

            var EndResult = result.ToList();

            Assert.AreEqual(EndResult.Count, 2);
        }            
    }
Run Code Online (Sandbox Code Playgroud)

有人能帮帮我吗? - >请告诉我在使用LINQ to Entities进行分组时如何保持排序.

das*_*ght 7

无论你在这里做什么,结果SQL都是一样的.

这是因为分组会破坏SQL中的顺序.ORDER BY子句在SQL的语法中排在最后SELECT.即使您设法将其压缩到子查询中,该标准也允许RDBMS在之后重新排序数据GROUP BY.使用的LINQ-to-Entities代码可以IQueryable<T>识别这一点,并忽略之前的所有排序GROUP BY.

要解决此问题,请OrderBy转到分组后运行的查询部分,例如

var result = persons
    .Where(p => p.Sex == Gender.Male || p.Sex == Gender.Female)
    .GroupBy(p => p.Sex)
    .Select(g => g.OrderBy(p => p.DateOfBirth).FirstOrDefault());
Run Code Online (Sandbox Code Playgroud)