データ ソースの null 値は不明な値を表します。LINQ to Entities クエリでは、NULL 値をチェックして、必ず NULL でない有効なデータを持つ行に特定の計算または比較を行うようにすることができます。ただし、CLR の NULL セマンティクスは、データ ソースの NULL セマンティクスとは異なる場合があります。ほとんどのデータベースでは、3 値論理を使用して NULL 比較を処理します。つまり、NULL 値との比較は true にも false にも評価されず、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
これは、NULL = NULL の比較が true を返す CLR の NULL セマンティクスとは大きく異なります。
次の 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 定数と比較される場合、または 2 つの NULL 定数が比較される場合、CLR の NULL セマンティクスが使用されます。データ ソースの NULL 値を持つ 2 つの列が比較される場合は、ストア NULL セマンティクスが使用されます。キー セレクタは、GroupBy など、グループ化や並べ替えの標準クエリ演算子で使用される場合が多く、クエリ結果の並べ替えやグループ化に使用するキーを選択できます。
NULL オブジェクトの NULL プロパティ
エンティティ フレームワーク では、NULL オブジェクトのプロパティは NULL です。CLR で NULL オブジェクトのプロパティを参照しようとすると、NullReferenceException が返されます。LINQ クエリに NULL オブジェクトのプロパティが含まれている場合、動作の一貫性が失われることがあります。
たとえば、次のクエリでは、NewProduct
へのキャストはコマンド ツリー レイヤで行われ、Introduced
プロパティが NULL になる可能性があります。DateTime の比較が true に評価されるように NULL 比較がデータベースで定義されている場合に、その行が含められます。
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);
}