Entity Framework renvoyant des données incorrectes

J'ai un projet Entity Framework 6.1 qui interroge une table de database SQL Server 2012 et récupère des résultats incorrects.

Pour illustrer ce qui se passe, j'ai créé 2 requêtes qui devraient avoir exactement les mêmes résultats. La table ProjectTable a 23 colonnes et 20500 lignes:

 var test1 = db.ProjectTable .GroupBy(t => t.ProjectOwner) .Select(g => g.Key) .ToArray(); var test2 = db.ProjectTable .ToArray() .GroupBy(t => t.ProjectOwner) .Select(g => g.Key) .ToArray(); 

Les requêtes sont conçues pour get une list de tous les propriétaires de projets distincts dans la table. La première requête effectue le gros du travail sur SQL Server, où la seconde requête télécharge la totalité de la table en memory, puis la traite côté client.

La première variable test1 a une longueur d'environ 300 éléments. La deuxième variable test2 a une longueur de 5.

Voici les requêtes SQL brutes générées par EF:

 -- test1 SELECT [Distinct1].[ProjectOwner] AS [ProjectOwner] FROM ( SELECT DISTINCT [Extent1].[ProjectOwner] AS [ProjectOwner] FROM [dbo].[ProjectTable] as [Extent1] ) AS [Distinct1] -- test2 SELECT Col1, Col2 ... ProjectOwner, ... Col23 FROM [dbo].[ProjectTable] 

Lorsque j'exécute cette requête et que j'parsing les entités renvoyées, je remarque que les lignes 20500ish complètes sont renvoyées, mais la colonne ProjectOwner est remplacée par l'un des 5 users différents!

 var test = db.ProjectTable.ToArray(); 

Je pensais que c'était peut-être le SQL Server, donc j'ai fait une trace de package et j'ai filtré sur TDS. Regardant au hasard les stream bruts, je vois beaucoup de noms qui ne sont pas dans la list des 5, donc je sais que datatables sont envoyées sur le fil correctement.

Comment puis-je voir datatables brutes qu'EF obtient? Y a-t-il quelque chose qui pourrait faire des dégâts dans le cache et entraîner des résultats incorrects?

Si j'exécute les requêtes dans SSMS ou Visual Studio, la list renvoyée est correcte. C'est seulement EF qui a ce problème.

MODIFIER

Ok, j'ai ajouté un autre test pour m'assurer que ma santé mentale est en échec. J'ai pris la requête sql crue de test2 j'ai fait ce qui suit:

 var test3 = db.Database .SqlQuery<ProjectTable>(@"SELECT Col1..Col23") .ToArray() .Select(t => t.ProjectOwner) .Distict() .ToArray(); 

et je récupère les 300 noms corrects!

Donc, en bref:

  1. Avoir EF envoyer la requête DISTINCT projetée à SQL Server renvoie les résultats corrects
  2. Avoir EF sélectionner la table entière et ensuite utiliser LINQ pour projeter et DISTINCT datatables returnnent des résultats incorrects
  3. Donner à EF la même question !!! cette puce # 2 génère et fait une requête SQL brute, renvoie les résultats corrects

Après avoir téléchargé la source Entity Framework et avoir parcouru plusieurs Enumerator , j'ai trouvé le problème.

Dans la méthode Shaper.HandleEntityAppendOnly ( trouvée ici ), à la ligne 187, la méthode Context.ObjectStateManager.FindEntityEntry est appelée. À ma grande surprise, une valeur non nulle a été returnnée! Attendez une minute, il ne devrait pas y avoir de résultats en cache, puisque je returnne toutes les lignes!

C'est quand j'ai découvert que ma table n'a pas de key primaire!

Pour ma défense, la table est en fait un cache d'une vue avec laquelle je travaille, je viens de faire un SELECT * INTO CACHETABLE FROM USERVIEW

J'ai ensuite regardé quelle colonne Entity Framework pensait être ma key primaire (ils l'appellent une key singleton) et il se trouve que la colonne qu'ils ont choisie n'avait que … drum roll s'il vous plaît5 valeurs uniques!

Quand j'ai regardé le model généré par EF, c'est sûr! Cette colonne a été spécifiée en tant que key primaire. J'ai changé la key pour la colonne appropriée et maintenant tout fonctionne comme il se doit!