Null 比较

数据源中的 null 值指示未知的值。在 LINQ to Entities 查询中,可以检查 null 值以便仅对具有有效(非 null)数据的行执行特定的计算或比较。但是,CLR null 语义可能与数据源的 null 语义不同。大多数数据库使用某个版本的三值逻辑处理 null 比较。即,对 null 值的比较不会计算为 truefalse,而是计算为 unknown。通常这是 ANSI null 值的实现,但情况并非总是如此。

在 SQL Server 中,null 等于 null 比较默认返回 null 值。在下面的示例中,Region 为 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

这与 CLR null 语义有很大差异,在 CLR null 语义中 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 常量进行比较或两个 null 常量进行比较,则会展现 CLR null 语义。如果数据源中具有 null 值的两个列进行比较,则会展现存储 null 语义。键选择器出现在许多分组和排序标准查询运算符(如 GroupBy)中,用于选择对查询结果进行排序或分组所依据的键。

Null 对象上的 Null 属性

在 实体框架 中,null 对象的属性为 null。当尝试引用 CLR 中的 null 对象的属性时,会收到 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 查询中的表达式