109 votes

Comment puis-je interroger les valeurs nulles dans Entity Framework?

Je veux exécuter une requête comme ceci

   var result = from entry in table
                     where entry.something == null
                     select entry;

et obtenir un IS NULL généré.

Édité: Après les deux premières réponses, je ressens le besoin de clarifier que j'utilise Entity Framework et non Linq to SQL. La méthode object.Equals() ne semble pas fonctionner dans EF.

Éditer n°2: La requête ci-dessus fonctionne comme prévu. Elle génère correctement IS NULL. Cependant, mon code de production était

valeur = null;
var result = from entry in table
                         where entry.something == valeur
                         select entry;

et le SQL généré était something = @p; @p = NULL. Il semble qu'EF traduise correctement l'expression constante, mais s'il y a une variable impliquée, elle la traite comme une comparaison normale. Cela a du sens en fait. Je vais clore cette question.

17 votes

Je pense que cela n'a pas vraiment de sens... Le connecteur devrait être un peu intelligent et ne pas nous demander de faire son travail : réaliser une traduction correcte en SQL d'une requête C# correcte. Cela génère un comportement inattendu.

6 votes

Je suis avec Julien, c'est un échec de la part de EF

1 votes

C'est un échec des normes, et cela empire encore maintenant que la comparaison avec null donne systématiquement undefined depuis SQL Server 2016 avec les ANCI NULL activés en permanence. Null peut représenter une valeur inconnue, mais "null" en soi n'est pas une valeur inconnue. La comparaison d'une valeur null avec une autre valeur null devrait absolument donner vrai, mais malheureusement la norme s'écarte du bon sens ainsi que de la logique booléenne.

125voto

Contournement pour Linq-to-SQL :

var result = from entry in table
             where entry.something.Equals(value)
             select entry;

Contournement pour Linq-to-Entities (aïe !) :

var result = from entry in table
             where (value == null ? entry.something == null : entry.something == value)
             select entry;

C'est un bug désagréable qui m'a affecté plusieurs fois. Si ce bug vous a également affecté, veuillez visiter le rapport de bug sur UserVoice et informez Microsoft que ce bug vous a également affecté.


Édition : Ce bug est en cours de correction dans EF 4.5 ! Merci à tous pour avoir voté pour ce bug !

Pour assurer la compatibilité descendante, ce sera une option - vous devez activer manuellement un paramètre pour que entry == value fonctionne. Aucun mot pour l'instant sur quel est ce paramètre. Restez à l'écoute !


Édition 2 : Selon cet article de l'équipe EF, ce problème a été résolu dans EF6 ! Hourra !

Nous avons modifié le comportement par défaut d'EF6 pour compenser la logique à trois valeurs.

Cela signifie que le code existant qui repose sur l'ancien comportement (null != null, mais seulement lorsqu'on compare à une variable) devra soit être modifié pour ne pas dépendre de ce comportement, soit définir UseCSharpNullComparisonBehavior sur false pour utiliser l'ancien comportement défectueux.

6 votes

J'ai voté pour le rapport de bug. Espérons qu'ils corrigent cela. Je ne peux pas dire que je me souvienne vraiment de ce bug étant présent dans la version bêta de vs2010...

2 votes

Oh viens microsoft... vraiment ?!? En version 4.1 ?!? +1

1 votes

Ce contournement de Linq-To-SQL semble ne pas fonctionner (en essayant avec un Guid?). Utiliser le contournement d'Entités fonctionne dans L2S, mais génère un SQL épouvantable. J'ai dû faire une déclaration if dans le code (var result = from ...; if(value.HasValue) result = result.Where(e => e.something == value) else result = result.Where(e => e.something == null);

17voto

ITmeze Points 511

Depuis Entity Framework 5.0, vous pouvez utiliser le code suivant pour résoudre votre problème :

public abstract class YourContext : DbContext
{
  public YourContext()
  {
    (this as IObjectContextAdapter).ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior = true;
  }
}

Cela devrait résoudre vos problèmes car Entity Framework utilisera une comparaison nulle 'C# like'.

16voto

divega Points 2935

Il existe une solution de contournement légèrement plus simple qui fonctionne avec LINQ to Entities :

var result = from entry in table
         where entry.something == value || (value == null && entry.something == null)
         select entry;

Cela fonctionne car, comme l'a remarqué AZ, LINQ to Entities traite de manière spéciale x == null (c'est-à-dire une comparaison d'égalité avec la constante null) et le traduit en x IS NULL.

Nous envisageons actuellement de modifier ce comportement pour introduire automatiquement les comparaisons compensatoires si les deux côtés de l'égalité sont nuls. Cependant, il y a quelques défis :

  1. Cela pourrait potentiellement casser du code qui dépend déjà du comportement existant.
  2. La nouvelle traduction pourrait affecter les performances des requêtes existantes même lorsque le paramètre nul est rarement utilisé.

Quoi qu'il en soit, que nous travaillions sur ce sujet dépendra grandement de la priorité relative que nos clients lui assignent. Si vous vous souciez de ce problème, je vous encourage à voter pour lui sur notre nouveau site de suggestion de fonctionnalités : https://data.uservoice.com.

9voto

Svish Points 32303

Si c'est un type nullable, essayez peut-être d'utiliser la propriété HasValue?

var result = from entry in table
                 where !entry.something.HasValue
                 select entry;

Je n'ai aucun EF à tester ici cependant... juste une suggestion =)

1 votes

Eh bien... cela ne fonctionne que si vous cherchez uniquement des valeurs nulles, mais ensuite en utilisant == null n'est de toute façon pas affecté par le bogue. Le point est de filtrer par la valeur d'une variable, dont la valeur pourrait être nulle, et d'avoir la valeur nulle trouver les enregistrements nuls.

1 votes

Votre réponse m'a sauvé. J'ai oublié d'utiliser un type nullable sur ma classe de modèle d'entité et je n'arrivais pas à faire fonctionner (x => x.Column == null). :)

0 votes

Cela donne System.NullReferenceException, car l'objet est déjà null!

5voto

Konstantin Tarkus Points 16862
var resultat = from entrée in table
             where entrée.quelqueChose.Equals(null)
             select entrée;

Référence MSDN: LINQ to SQL: .NET Language-Integrated Query for Relational Data

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X