Поделиться через


Сравнения со значением Null

Значение null в источнике данных указывает на то, что это значение неизвестно. В запросах LINQ to Entities можно реализовать проверку наличия значений NULL так, чтобы определенные вычисления или сравнения выполнялись только для строк с допустимыми данными, не содержащими значений NULL. Впрочем, null-семантика среды CLR может отличаться от null-семантики источника данных. В большинстве баз данных для выполнения сравнений со значением Null используется трехзначная логика. Иначе говоря, результат сравнения со значением Null не дает ни true, ни false; в результате получается значение unknown. Часто речь идет о реализациях Null ANSI, но так бывает не всегда.

По умолчанию в SQL Server сравнение «Null равняется Null» возвращает значение Null. В следующем примере строки, где параметр «Регион» имеет значение Null, исключаются из результирующего набора и инструкция Transact-SQL возвращает 0 строк.

-- Find orders and customers with no regions.
SELECT a.[CustomerID] 
FROM [Northwind].[dbo].[Customers] a
JOIN [Northwind].[dbo].[Orders] b ON a.Region = b.ShipRegion
WHERE a.Region IS Null

Это совсем не похоже на Null-семантику среды CRL, где сравнение «Null равняется Null» возвращает значение True.

Следующий запрос LINQ выражается в среде CLR, но выполняется в источнике данных. Гарантии того, что семантика CLR будет действительна для среды источника данных, не существует, поэтому предполагаемое поведение непредсказуемо.

Using NwEntities As New NorthwindEntities()
    Dim customers As ObjectQuery(Of Customers) = NwEntities.Customers
    Dim orders As ObjectQuery(Of Orders) = NwEntities.Orders

    Dim query = _
        From c In customers _
        Join o In orders On c.Region Equals o.ShipRegion _
        Where c.Region = Nothing _
        Select c.CustomerID

    For Each customerID In query
        Console.WriteLine("Customer ID: ", customerID)
    Next
End Using
using (NorthwindEntities NwEntities = new NorthwindEntities())
{
    ObjectQuery<Customers> customers = NwEntities.Customers;
    ObjectQuery<Orders> orders = NwEntities.Orders;

    IQueryable<string> query = from c in customers
                                  join o in orders on c.Region equals o.ShipRegion
                                  where c.Region == null
                                  select c.CustomerID;

    foreach (string customerID in query)
    {
        Console.WriteLine("Customer ID: {0}", customerID);
    }
}

Селекторы ключей

Селектор ключа — функция, используемая в стандартных операторах запросов для извлечения ключа из элемента. В функции селектора элемента может быть выполнено сравнение выражения с константой. Null-семантика CLR проявляется в тех случаях, когда выражение сравнивается с константой, имеющей значение Null, или когда сравниваются две константы со значениями Null. Null-семантика хранилищ проявляется в тех случаях, когда сравниваются два столбца источника данных со значениями Null. Селекторы ключей входят в состав многих используемых в запросах стандартных операторов группирования и упорядочивания, например GroupBy, и применяются для выделения ключей, по которым будет осуществляться упорядочение или группирование результатов запроса.

Свойство Null объекта Null

В Entity Framework свойства объекта Null имеют значения Null. При попытке обратиться к свойству объекта Null в среде CLR пользователь получает исключение NullReferenceException. Когда в LINQ-запросе задействовано свойство объекта Null, может быть получен несогласованный результат.

Так, в следующем примере приведение к типу NewProduct осуществляется на уровне дерева команд. В результате может получиться так, что свойство Introduced будет иметь значение Null. Если определенные в базе данных сравнения со значением Null таковы, что сравнение с DateTime дает значение True, то соответствующая строка будет включена.

Using AWEntities As New AdventureWorksEntities()
    Dim dt As DateTime = New DateTime()
    Dim query = AWEntities.Product _
        .Where(Function(p) _
            ((DirectCast(p, NewProduct)).Introduced > dt)) _
        .Select(Function(x) x)
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{

    DateTime dt = new DateTime();
    var query = AWEntities.Product
        .Where(p => (p as NewProduct).Introduced > dt)
        .Select(x => x);
}

См. также

Основные понятия

Выражения в запросах LINQ to Entities