Comparações nulas
Um valor null
na fonte de dados indica que o valor é desconhecido. Nas consultas do LINQ to Entities, você pode procurar valores nulos de modo que determinados cálculos ou comparações só sejam executados nas linhas que têm dados válidos ou não nulos. A semântica nula do CLR, no entanto, pode diferir da semântica nula da fonte de dados. A maioria dos bancos de dados usa uma versão da lógica de três valores para manipular comparações nulas. Ou seja, uma comparação com um valor nulo não é avaliada como true
ou false
; ela é avaliada como unknown
. Geralmente, essa é uma implementação de valores nulos ANSI, mas isso nem sempre acontece.
Por padrão, no SQL Server, a comparação nulo igual a nulo retorna um valor nulo. No exemplo a seguir, as linhas em que ShipDate
é null serão excluídas do conjunto de resultados, e a instrução Transact-SQL retornará 0 linhas.
-- 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
Isso é muito diferente de semântica nula do CLR, em que a comparação de null igual a null retorna true.
A seguinte consulta LINQ é expressa no CLR, mas é executada na fonte de dados. Como não há nenhuma garantia de que a semântica do CLR será respeitada na fonte de dados, o comportamento esperado será indeterminado.
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
Seletores de chave
Um seletor de chave é uma função usada nos operadores de consulta padrão para extrair uma chave de um elemento. Na função do seletor de chave, uma expressão pode ser comparada a uma constante. A semântica nula do CLR será exibida se uma expressão for comparada com uma constante nula ou se duas constantes nulas forem comparadas. As semânticas nulas de armazenamento serão exibidas se duas colunas com valores nulos na fonte de dados forem comparadas. Os seletores de chave são encontrados em muitos operadores de consulta padrão de agrupamento e ordenação, como GroupBy, e usados para selecionar as chaves que servirão de base para a ordenação ou o agrupamento do resultados da consulta.
Propriedade nula em um objeto nulo
No Entity Framework, as propriedades de um objeto nulo são nulas. Ao tentar fazer referência à propriedade de um objeto nulo no CLR, você receberá NullReferenceException. Quando uma consulta LINQ envolver uma propriedade de um objeto nulo, o resultado possivelmente será um comportamento inconsistente.
Por exemplo, na consulta a seguir, a conversão em NewProduct
é feita na camada da árvore de comandos, que pode resultar na propriedade Introduced
que está sendo nula. Se o banco de dados tiver definido comparações nulas, como a comparação DateTime que é avaliada como true, a linha será incluída.
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
Passando coleções nulas para funções agregadas
No LINQ to Entities, quando você passa uma coleção que oferece suporte a IQueryable
para uma função agregada, as operações agregadas são executadas no banco de dados. Talvez haja diferenças nos resultados de uma consulta executada na memória e de uma consulta executada no banco de dados. Com uma consulta de memória, se não houver nenhuma correspondência, a consulta retornará zero. No banco de dados, a mesma consulta retorna null
. Se um valor null
for passado para uma função agregada LINQ, uma exceção será lançada. Para aceitar os valores null
possíveis, converta os tipos e as propriedades dos tipos que recebem resultados de consulta em tipos que permitem valores nulos.