2017-10-23 3 views
4

Ich verwende EF 6, um einige Daten von SQL Server abzurufen. Ich bin in der Vergangenheit auf dieses Problem gestoßen, aber ich habe niemanden danach gefragt.Daten abrufen, merkwürdiges Verhalten

Für den folgenden Code, nur auf die Auswahl konzentrieren.

Sagen wir mal in der Datenbank Ich habe 2 Reihen:

1 2 3 4 5 
6 7 8 9 10 

Mein Code:

var results = db.Table.Where(o => o.Version == 1) 
         .Select(o => new List<double?>{ o.M01, o.M02, o.M03, o.M04, o.M05}); 

return results.ToList(); 

Der obige Code wird eine Liste von Listen mit folgenden zurück:

previousDemand[0] = 1 2 3 4 5 
previousDemand[1] = 10 9 8 7 6 

Die zweite Liste ist umgekehrt.

Wenn ich mehr Zeilen habe, passiert es das gleiche: zuerst ok, zweite umgedreht, dritte ok, vierte umgedreht und so weiter.

Wenn ich ändern Sie den Code dazu:

var results = db.Table.Where(o => o.Version == 1).ToList(); 
var x = results.Select(o => new List<double?>{ o.M01, o.M02, o.M03, o.M04, o.M05}); 

return x.ToList(); 

hier alles gut funktionieren wird.

Wenn scheint, gibt es ein Problem, wenn ich Listen innerhalb der EF-Abfrage erstellen.

Fehle ich etwas Wichtiges?

UPDATE Hinzufügen einiger Screenshots: Sql Server

What i receive in EF

+0

Und wie generierte SQL Abfragen in beiden Fällen aussieht? – Reniuz

+4

Da Sie nicht explizit nach einer bestimmten Reihenfolge fragen und gegen SQL Server vorgehen, ist die Reihenfolge, in der die Werte zurückgegeben werden, ** nicht definiert ** - SQL Server kann sie kostenlos zurückgeben jede Bestellung, die es tun könnte. Wenn Sie ** ** bestellen müssen - dann müssen Sie ** explizit definieren ** - mit einem '.OrderBy' in EF oder einem' ORDER BY' In T-SQL –

Antwort

2

Dies ist ein reproduzierbarer Fehler in der Art und Weise, wie EF ein List<T> Objekt aus Werten erzeugt, die von einem Datenbankdatensatz stammen. Es stellt sich heraus, dass die ausgeführte SQL-Anweisung die Werte in dieser unerwarteten alternierenden Reihenfolge zurückgibt. Das bedeutet, dass EF eine SQL-Abfrage generiert, die niemals eine bestimmte Reihenfolge zurückgibt. Da SQL jedoch eine set-basierte Sprache ist, gibt es keine Garantie für die Reihenfolge der Elemente in einem Set. Es wäre möglich, eine Abfrage-SQL zu generieren, die die Elemente korrekt anordnet, aber ich denke, EF hat Ihr (nicht so häufiges) Szenario nie vorausgesehen oder es hat sich nicht gelohnt, es zu unterstützen.

Da es Teil des Quellcodes von EF ist, gibt es keinen schnellen Weg, es zu beheben, und Sie müssen sich mit Ihrem Workaround zufrieden geben. Vielleicht möchten Sie einen Fehlerbericht einreichen.

Das Stammproblem IMO ist schlechte Datennormalisierung. Wenn Ihre Tabelle das übergeordnete Element einer Tabelle mit M Datensätzen wäre - wobei jeder einen doppelten Wert darstellt, möglicherweise mit einem Sequenzfeld -, wäre es viel einfacher, diese Liste von Listen zu erhalten.

4

TL; DR

new List<double?> { o.M01, o.M02, o.M03, o.M04, o.M05 }.OrderBy(p => p).ToList()

Diese Umfrage funktioniert nur mit der von Ihnen bereitgestellten Stichprobe, löst Ihr Problem jedoch nicht, wie @GertArnold auf die Kommentare hingewiesen hat.

Stattdessen können Sie nicht nach einer Liste suchen, sondern eine neue Entität mit den gewünschten Spalten zurückgeben. Nachdem Sie das Ergebnis materialisiert haben, können Sie es in eine Liste umwandeln.

var results = 
    db.Entities.Where(o => o.Version == 1) 
    .Select(o => new { M01 = o.M01, M02 = o.M02, M03 = o.M03, M04 = o.M04, M05 = o.M05 }); 

return results.Select(o => new List<double?> { o.M01, o.M02, o.M03, o.M04, o.M05 }); 

Nun ist die Argumentation:

Ihre EF-Abfrage generiert die folgende (wirklich chaotisch) SQL-Anweisung:

SELECT 
    [Project6].[Id] AS [Id], 
    [Project6].[C2] AS [C1], 
    [Project6].[C1] AS [C2] 
    FROM ( 
     SELECT 
      CASE 
       WHEN ([UnionAll4].[C1] = 0) THEN [Extent1].[M01] 
       WHEN ([UnionAll4].[C1] = 1) THEN [Extent1].[M02] 
       WHEN ([UnionAll4].[C1] = 2) THEN [Extent1].[M03] 
       WHEN ([UnionAll4].[C1] = 3) THEN [Extent1].[M04] 
       ELSE [Extent1].[M05] END AS [C1], 
      [Extent1].[Id] AS [Id], 
      1 AS [C2] 
     FROM [dbo].[Entities] AS [Extent1] 
     CROSS JOIN (
      SELECT 0 AS [C1] 
      FROM (SELECT 1 AS X) AS [SingleRowTable1]     
      UNION ALL    
       SELECT 1 AS [C1] 
       FROM (SELECT 1 AS X) AS [SingleRowTable2]     
      UNION ALL    
       SELECT 2 AS [C1] 
       FROM (SELECT 1 AS X) AS [SingleRowTable3]    
      UNION ALL    
       SELECT 3 AS [C1] 
       FROM (SELECT 1 AS X) AS [SingleRowTable4]     
      UNION ALL    
       SELECT 4 AS [C1] 
       FROM (SELECT 1 AS X) AS [SingleRowTable5] 
      ) AS [UnionAll4] 
      WHERE 1 = [Extent1].[Version] 
    ) AS [Project6] 
ORDER BY [Project6].[Id] ASC, [Project6].[C2] ASC 

Wie Sie auf der ORDER BY-Klausel sehen können, die Abfrage Aufträge von [Project6]. [C2], was nur ein Kontroll-Flag ist, das 1 zurückgibt. Dies liegt daran, dass Sie, wie in den Kommentaren angegeben, @marc_s nicht explizit eine Reihenfolge für Ihre Ergebnisse angegeben haben.

Wenn du stattdessen verwenden somenting wie:

var results = db.Entities.Where (o => o.Version == 1) .Select (o => neue Liste {o. M01, o.M02, o.M03, o.M04, o.M05} .OrderBy (p => p) .ToList());

... dann würde das generierte SQL die korrekte Bestellklausel enthalten und Sie würden das erhaltene Ergebnis erhalten.

var results = 
    db.Entities.Where(o => o.Version == 1) 
    .Select(o => new { M01 = o.M01, M02 = o.M02, M03 = o.M03, M04 = o.M04, M05 = o.M05 }); 

return results.Select(o => new List<double?> { o.M01, o.M02, o.M03, o.M04, o.M05 }); 

... dann würden Sie nicht mit dem generierten SQL, um stören müssen und die Kontrolle über den Auftrag haben, würde Ihre Spalten auf der Ausgabeliste zurückgegeben werden.

+0

Aber M01, M02, M03, M04, M05 sind Spalten einer Tabelle. Wie sieht die EF-Mapping-erste Zeile aus: M01 = 1, M02 = 2, M03 = 3, M04 = 4, M05 = 5 und die zweite Zeile wie: M01 = 10, M02 = 9, M03 = 8, M04 = 7, M05 = 6? Order by bestellt die Ergebnisse. Meine Frage besteht darin, die Spalten einer Zeile falsch zuzuordnen, und nicht darauf, wie die Ergebnisse geordnet sind. Vielleicht war ich unklar. Ich werde einige Screenshots veröffentlichen, um später genauer darauf eingehen zu können. –

+0

@ BogdanC. Sie ordnen Ihre Ergebnisse einer Liste zu. Es ist nichts falsch mit der Zuordnung von EF, aber mit dem, was Sie damit tun, Wenn Sie Ihr Ergebnis z. B. einer neuen Klasse mit den fünf Requisiten zuordnen würden, hätten Sie nicht das Problem, dass SQL eine beliebig geordnete zurückgibt Ergebnismenge, die zu einer Liste hinzugefügt wurde. Versuchen Sie etwas wie 'Wählen Sie (o => neu {M01 = o.M01, M02 = o.M02, M03 = o.M03, M04 = o.M04, M05 = o.M05});' um zu sehen, was ich ' ich rede darüber. –

+0

@ BogdanC. Übrigens, hast du die von mir vorgeschlagene Lösung ausprobiert? Ich bin sicher, dass es Ihr Problem beheben wird ... –