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

时间:2016-11-28 13:43:42

标签: c# entity-framework linq

这是正常的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;
    }
}
}

但是当您将数据插入数据库并尝试在使用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);
        }            
    }

有人可以帮帮我吗? - &GT;请告诉我在使用LINQ to Entities进行分组时如何保持排序。

2 个答案:

答案 0 :(得分:7)

  

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

这是因为分组会破坏SQL中的顺序。 ORDER BY子句在SQL SELECT的语法中排在最后。即使您设法将其压缩到子查询中,该标准也允许RDBMS在GROUP BY之后重新排序数据。与IQueryable<T>一起使用的LINQ-to-Entities代码识别出这一点,并忽略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());

答案 1 :(得分:0)

使用上面的答案,我能够重新编写我的代码,从而产生了这个成功的测试:

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

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

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

            var oldestMales = oldest.Where(x => x.All(q => q.Sex == Gender.Male)).FirstOrDefault();
            var oldestFemales = oldest.Where(x => x.All(q => q.Sex == Gender.Female)).FirstOrDefault();

            var oldestWoman = oldestFemales.FirstOrDefault();
            var oldestMan = oldestMales.FirstOrDefault();

            var youngestMales = youngest.Where(x => x.All(q => q.Sex == Gender.Male)).FirstOrDefault();
            var youngestFemales = youngest.Where(x => x.All(q => q.Sex == Gender.Female)).FirstOrDefault();

            var youngestWoman = youngestFemales.FirstOrDefault();
            var youngestMan = youngestMales.FirstOrDefault();                

            Assert.AreEqual(oldestWoman.Name, "Navya"); //Oldest Woman
            Assert.AreEqual(oldestMan.Name, "Pranav"); //Oldest Man 

            Assert.AreEqual(youngestMan.Name, "Aditya"); // Youngest Man
            Assert.AreEqual(youngestWoman.Name, "Ananya"); // Youngest Woman
        }
    }

请注意:您不能只使用FirstOrDefault(),因为分组本身并未订购。这就是我需要这样做的原因:

var oldestFemales = oldest.Where(x => x.All(q => q.Sex == Gender.Female)).FirstOrDefault();

我接受了答案。非常感谢你!