Udostępnij za pośrednictwem


Porównania wartości null

null Wartość w źródle danych wskazuje, że wartość jest nieznana. W zapytaniach LINQ to Entities można sprawdzać wartości nullowe, aby niektóre obliczenia lub porównania były wykonywane tylko w wierszach z prawidłowymi lub niepustymi danymi. Semantyka wartości null CLR może jednak różnić się od semantyki wartości null źródła danych. Większość baz danych używa wersji trzywartościowej logiki do obsługi porównań o wartości null. Oznacza to, że porównanie z wartością null nie jest równe true ani false, lecz jest równe unknown. Często jest to implementacja wartości null ANSI, ale nie zawsze tak jest.

Domyślnie w programie SQL Server porównanie null-equals-null zwraca wartość null. W poniższym przykładzie wiersze, w których ShipDate wartość null jest wykluczona z zestawu wyników, a instrukcja Transact-SQL zwróci 0 wierszy.

-- 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  

Różni się to zupełnie od semantyki null CLR, gdzie porównanie null-equals-null zwraca wartość true.

Następujące zapytanie LINQ jest wyrażone w clR, ale jest wykonywane w źródle danych. Ponieważ nie ma gwarancji, że semantyka CLR będzie honorowana w źródle danych, oczekiwane zachowanie jest nieokreślone.

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 : {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

Główne selektory

Selektor kluczy to funkcja używana w standardowych operatorach zapytań do wyodrębniania klucza z elementu. W funkcji selektora kluczy wyrażenie można porównać ze stałą. Semantyka wartości null CLR występuje, jeśli wyrażenie jest porównywane ze stałą 'null' lub gdy porównywane są dwie stałe 'null'. Semantyka przechowywania wartości null ujawnia się, gdy porównywane są dwie kolumny z wartościami null w źródle danych. Selektory kluczy znajdują się w wielu operatorach grupowania i porządkowania standardowych operatorów zapytań, takich jak GroupBy, i służą do wybierania kluczy, według których należy porządkować lub grupować wyniki zapytania.

Właściwość Null w obiekcie null

W programie Entity Framework właściwości obiektu nullowego mają wartość null. Podczas próby odwołania do właściwości obiektu o wartości null w clR zostanie wyświetlony element NullReferenceException. Gdy zapytanie LINQ obejmuje właściwość obiektu o wartości null, może to spowodować niespójne zachowanie.

Na przykład w poniższym zapytaniu przekształcenie do NewProduct jest wykonywane w warstwie drzewa poleceń, co może spowodować, że właściwość Introduced będzie mieć wartość null. Jeśli w bazie danych zdefiniowano porównania z wartościami null w taki sposób, że porównanie DateTime daje wartość true, wiersz zostanie uwzględniony.

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

Przekazywanie kolekcji null do funkcji agregujących

W LINQ to Entities, gdy przekażesz kolekcję obsługującą IQueryable do funkcji agregacji, operacje agregujące są wykonywane w bazie danych. Mogą istnieć różnice w wynikach zapytania, które zostało wykonane w pamięci i zapytaniu, które zostało wykonane w bazie danych. W przypadku zapytania w pamięci, jeśli nie ma dopasowań, zapytanie zwraca zero. W bazie danych to samo zapytanie zwraca wartość null. Jeśli wartość null zostanie przekazana do funkcji agregującej LINQ, zostanie zgłoszony wyjątek. Aby zaakceptować możliwe wartości null, przekształć typy oraz właściwości typów, które odbierają wyniki zapytania, na typy wartości dopuszczające wartość null.

Zobacz też