2016-11-28 1 views
9

Gruppierung ist das normal LINQ, und dieser Test erfolgreich:LINQ im Vergleich zu LINQ to Entities, halten, wenn

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; 
    } 
} 
} 

Aber wenn Sie die Daten in eine Datenbank einfügen und versuchen, das gleiche zu tun, wenn LINQ to Entities mit Es scheint, als ob die resultierende SQL die gleiche ist, unabhängig von der angewendeten Sortierung.

[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); 
     }    
    } 

Kann mir bitte jemand helfen? -> Bitte zeigen Sie mir, wie ich bei der Gruppierung bei der Verwendung von LINQ to Entities meine Sortierung beibehalten kann.

+0

Sind Sie sicher, dass die Methode 'GetTestPersons()' das gleiche Ergebnis liefert wie 'context.Persons'? –

Antwort

7

Unabhängig davon, was Sie hier tun, ist das resultierende SQL das gleiche.

Dies ist, weil die Gruppierung die Reihenfolge in SQL zerstört. ORDER BY Klausel kommt zuletzt in der Syntax von SQL SELECT. Selbst wenn Sie es schaffen, es in eine Unterabfrage zu pressen, erlaubt der Standard RDBMS, Daten nach GROUP BY neu zu ordnen. LINQ-to-Entities-Code, der mit IQueryable<T> arbeitet, erkennt dies und ignoriert alle Bestellungen vor GROUP BY.

dieses Problem beheben, OrderBy zum Teil Ihrer Abfrage bewegen, die nach der Gruppierung ausgeführt wird, zum Beispiel

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()); 
0

die Antwort oben verwendet, konnte ich mein Code neu schreiben in diesem nachfolgenden Test resultierende :

[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 
     } 
    } 

Bitte beachten Sie: Sie können nicht nur verwenden FirstOrDefault(), weil die Gruppierung selbst nicht bestellt wird. Deshalb muss ich folgendes tun:

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

Ich akzeptiere die Antwort nichtsdestotrotz. Vielen Dank!