2013-01-03 8 views
8

J'ai deux requêtes similaires qui reviennent théoriquement les mêmes résultats:Comportement inattendu Linq - ToList()

var requestNotWorking = SessionManagement.Db.Linq<Item>(false).Where(i => 
         i.Group != null && i.Group.Id == methodParameter) 
         .ToList(); 

Cette demande renvoie 0 articles, même si elle est censée retourner un. Voici une réécriture de ce dernier, mais avec un appel à la méthode ToList(). Cette requête fonctionne et renvoie l'élément attendu dans la première requête!

var requestWorking = SessionManagement.Db.Linq<Item>(false).ToList().Where(i => 
        i.Group != null && i.Group.Id == methodParameter).ToList(); 

Note: SessionManagement.Db.Linq<Item>(false) est un Linq générique à la méthode Nhibernate avec l'attribut booléen déterminant si doit être exécutée la demande dans le cache (true) ou la base de données (false). Il n'y a apparemment rien de mal dans cette méthode car cela fonctionne normalement dans beaucoup d'autres parties de la solution. La cartographie de l'article n'a rien de fantaisie: pas de sacs et les paramètres suivants: lazy="false" schema="dbo" mutable="false" polymorphism="explicit"

Pourquoi est-ce ainsi?

Modifier:

La requête SQL généré des requestNoWorking se termine par:

(Item.Group_ID is not null) and [email protected]',N'@p0 int',@p0=11768

La requête SQL généré de requestWorking est à peu près un select * from dbo.Items

+1

Si vous utilisez Sql Server, avez-vous essayé d'exécuter SQL Profiler lors de l'exécution de ces deux requêtes? – nerdybeardo

+0

i.Group diffère entre les deux. Nom identique, mais complètement différent quand sur différents types de collections. –

+1

Veuillez publier le code SQL généré. Il y a une différence sémantique entre ce que le SQL fait et ce que la sémantique C# dicte. LINQ ne promet pas de sémantique identique. – usr

Répondre

1

J'ai été très intéressé par votre théorie sur c.Group.Id != null, que j'ai trouvé logique même si elle contredit d'autres morceaux de code dans ma solution. Cependant, l'enlever n'a rien changé. J'ai trouvé que la suppression de la propriété mutable="false" a résolu le problème. Cela semble un peu magique mais ça a marché.

Les requêtes que j'ai postées se passaient en fait dans des méthodes vérifiant la possibilité de mise à jour/suppression. Ma conclusion est que, d'une manière ou d'une autre, rendre un objet immuable a faussé les résultats. Mais ce que je ne comprends pas, c'est pourquoi requestWorking a travaillé alors!

0

Tout ce que je peux voir est que dans la 2ème version, votre Where est exécuté par LINQ to Objects plutôt que LINQ to NHibernate. La première version doit donc faire quelque chose que LINQ to NHibernate ne digère pas très bien.

Je suis penser c'est le i.Group != null que LINQ Pour NHibernate a un problème avec, en voyant que l'utilisation de null est spécifique CLR. Vous devrez peut-être utiliser une autre construction dans LINQ to NHibernate pour tester les valeurs de champs vides.

4

Je suppose que la chose nhibernate session que vous avez là-bas renvoie un questionable. si c'est le cas, l'évaluation de la première requête est retardée jusqu'à l'appel .ToList(), et la requête entière est exécutée sur le serveur. Je suggère que vous exécutiez une trace sur le serveur sql si possible, ou peut-être télécharger NHProf pour voir ce que la requête réelle en cours d'exécution est.

La deuxième requête est évaluée dès que vous appuyez sur la première .ToList(), de sorte que vous récupérez toute la table à partir de la base de données, puis filtrez en utilisant .net. Honnêtement, je ne peux pas vous dire pourquoi ils évalueraient différemment, mais je suppose qu'il y a quelque chose avec le mappage/configuration qui provoque l'écriture de la requête db légèrement faux.

+3

Ma conjecture serait quelque chose autour de la comparaison nulle, les comparaisons SQL NULL sont toujours PITA. – anydot