Partager via


Comparaisons null

Une valeur null dans la source de données indique que la valeur est inconnue. Dans les requêtes LINQ to Entities, vous pouvez vérifier les valeurs Null afin que certains calculs ou certaines comparaisons soient effectués uniquement sur les lignes qui ont des données valides, ou non Null. Toutefois, la sémantique Null CLR peut différer par rapport à la sémantique Null de la source de données. La plupart des bases de données utilisent une version de logique à trois valeurs pour gérer les comparaisons de valeurs Null. Autrement dit, une comparaison avec une valeur Null n'a pas la valeur true ou false ; elle a la valeur unknown. Il s'agit souvent d'une implémentation de valeurs ANSI Null, mais ce n'est pas toujours le cas.

Par défaut dans SQL Server, la comparaison Null-égale-Null retourne une valeur Null. Dans l'exemple suivant, les lignes dans lesquelles ShipDate a la valeur Null sont exclues du jeu de résultats, et l'instruction Transact-SQL retournerait 0 ligne.

-- Find order details and orders with no ship date.  
SELECT h.SalesOrderID  
FROM Sales.SalesOrderHeader h  
JOIN Sales.SalesOrderDetail o ON o.SalesOrderID = h.SalesOrderID  
WHERE h.ShipDate IS Null  

C'est très différent de la sémantique Null CLR, où la comparaison Null-égale-Null retourne true.

La requête LINQ suivante est exprimée dans le CLR, mais elle est exécutée dans la source de données. Étant donné que rien ne garantit que la sémantique CLR sera respectée au niveau de la source de données, le comportement attendu est indéterminé.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    ObjectSet<SalesOrderHeader> orders = context.SalesOrderHeaders;
    ObjectSet<SalesOrderDetail> details = context.SalesOrderDetails;

    var query =
        from order in orders
        join detail in details
        on order.SalesOrderID
        equals detail.SalesOrderID
        where order.ShipDate == null
        select order.SalesOrderID;

    foreach (var OrderID in query)
    {
        Console.WriteLine("OrderID : {0}", OrderID);
    }
}
Using context As New AdventureWorksEntities()

    Dim orders As ObjectSet(Of SalesOrderHeader) = context.SalesOrderHeaders
    Dim details As ObjectSet(Of SalesOrderDetail) = context.SalesOrderDetails

    Dim query = _
        From order In orders _
        Join detail In details _
        On order.SalesOrderID _
        Equals detail.SalesOrderID _
        Where order.ShipDate = Nothing
        Select order.SalesOrderID


    For Each orderID In query
        Console.WriteLine("OrderID: {0} ", orderID)
    Next
End Using

Sélecteurs de clé

Un sélecteur de clé est une fonction utilisée dans les opérateurs de requête standard pour extraire une clé d'un élément. Dans la fonction du sélecteur de clé, une expression peut être comparée avec une constante. La sémantique Null CLR est exposée si une expression est comparée à une constante Null ou si deux constantes Null sont comparées. La sémantique Null du magasin est exposée si deux colonnes contenant des valeurs Null dans la source de données sont comparées. Les sélecteurs de clé, qui se trouvent dans un grand nombre des opérateurs de requête standard de classement et de regroupement, tels que GroupBy, sont utilisés pour sélectionner les clés sur lesquelles trier ou regrouper les résultats de la requête.

Propriété Null sur un objet Null

Dans Entity Framework, les propriétés d'un objet Null sont Null. Lorsque vous essayez de référencer une propriété d'un objet Null dans le CLR, vous recevez un objet NullReferenceException. Lorsqu'une requête LINQ implique une propriété d'un objet Null, cela peut provoquer un comportement incohérent.

Par exemple, dans la requête suivante, le cast en NewProduct est effectué dans la couche de l’arborescence de commandes, ce qui peut rendre Null la propriété Introduced. Si la base de données a défini des comparaisons de valeurs Null telles que la comparaison DateTime ait la valeur true, la ligne sera incluse.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{

    DateTime dt = new DateTime();
    var query = context.Products
        .Where(p => (p as NewProduct).Introduced > dt)
        .Select(x => x);
}
Using context As New AdventureWorksEntities()
    Dim dt As DateTime = New DateTime()
    Dim query = context.Products _
        .Where(Function(p) _
            ((DirectCast(p, NewProduct)).Introduced > dt)) _
        .Select(Function(x) x)
End Using

Transmission de collections de valeurs Null aux fonctions d’agrégation

Dans LINQ to Entities, lorsque vous passez une collection qui prend en charge IQueryable à une fonction d’agrégation, les opérations d’agrégation sont effectuées dans la base de données. Il peut y avoir des différences entre les résultats d'une requête qui a été effectuée en mémoire et ceux d'une requête qui a été effectuée dans la base de données. Avec une requête en mémoire, en l'absence de correspondance, la requête retourne zéro. Dans la base de données, la même requête retourne la valeur null. Si une valeur null est transmise à une fonction d'agrégation LINQ, une exception est levée. Pour accepter les éventuelles valeurs null, transtypez les types et les propriétés des types qui reçoivent les résultats de la requête en types de valeur Nullable.

Voir aussi