Comparaciones NULL

Un valor null en el origen de datos indica que el valor es desconocido. En las consultas de LINQ to Entities, puede comprobar si ha valores NULL para que ciertos cálculos o comparaciones solo se realicen en las filas que tengan datos válidos, que no sean NULL. Sin embargo, la semántica de NULL de CLR puede diferir de la del origen de datos. La mayoría de las bases de datos utilizan una versión de lógica con tres valores para tratar las comparaciones de NULL. Es decir, una comparación con un valor NULL no se evalúa como true o false, se evalúa como unknown. A menudo ésta es una implementación de los valores NULL ANSI, pero este no es siempre el caso.

De forma predeterminada en SQL Server, al comparar si un valor NULL es igual a un valor NULL, se devuelve un valor NULL. En el ejemplo siguiente, las filas donde ShipDate es NULL se excluyen del conjunto de resultados y la instrucción Transact-SQL devolvería 0 filas.

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

Esto es muy diferente de la semántica de NULL de CLR, donde la comparación de igualdad entre valores NULL devuelve true.

La consulta de LINQ siguiente se expresa en el CLR, pero se ejecuta en el origen de datos. Dado que no hay ninguna garantía de que la semántica de CLR se vaya a cumplir en el origen de datos, el comportamiento esperado es 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

Selectores de clave

Un selector de clave es una función utilizada en los operadores de consulta estándar para extraer una clave de un elemento. En la función de selector de clave, una expresión se puede comparar con una constante. La semántica de NULL del CLR se exhibe si una expresión se compara con una constante NULL o si se comparan dos constantes NULL. La semántica de NULL del almacén se exhibe si se comparan dos columnas con valores NULL del origen de datos. Los selectores de clave se encuentran en muchos de los operadores de consulta estándar de agrupamiento y ordenación, como GroupBy, y se utilizan para seleccionar las claves por las que ordenar o agrupar los resultados de una consulta.

Propiedad NULL en un objeto NULL

En el Entity Framework, las propiedades de un objeto NULL son NULL. Al intentar hacer referencia a una propiedad de un objeto NULL en el CLR, recibirá NullReferenceException. Cuando una consulta de LINQ implica una propiedad de un objeto NULL, puede provocarse un comportamiento incoherente.

Por ejemplo, en la consulta siguiente, la conversión a NewProduct se efectúa en el nivel de árbol de comandos, que podría hacer que la propiedad Introduced sea NULL. Si la base de datos definió las comparaciones de NULL de modo que la comparación de DateTime se evalúe como true, la fila se incluirá.

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

Pasar colecciones NULL a funciones de agregado

En LINQ to Entities, al pasar una colección que admite IQueryable a una función de agregado, las operaciones de agregado se realizan en la base de datos. Podría haber diferencias entre los resultados de una consulta que se realizó en memoria y una consulta que se realizó en la base de datos. En una consulta en memoria, si no hay ninguna coincidencia, la consulta devuelve el cero. En la base de datos, la misma consulta devuelve null. Si se pasa un valor null a una función de agregado de LINQ, se producirá una excepción. Para aceptar los valores null posibles, convierta los tipos y las propiedades de los tipos que reciben los resultados de la consulta a tipos de valores que aceptan valores NULL.

Consulte también