データ ソースの null 値は、値が不明であることを示します。 LINQ to Entities クエリでは、null 値をチェックして、特定の計算または比較が有効なデータまたは null 以外のデータを持つ行に対してのみ実行されるようにすることができます。 ただし、CLR の null セマンティクスは、データ ソースの null セマンティクスとは異なる場合があります。 ほとんどのデータベースでは、3 つの値を持つロジックのバージョンを使用して null 比較を処理します。 つまり、null 値に対する比較は、 true または falseに評価されず、 unknownに評価されます。 多くの場合、これは ANSI null の実装ですが、必ずしもそうであるとは限りません。
SQL Server の既定では、null-equals-null 比較では null 値が返されます。 次の例では、 ShipDate が null の行は結果セットから除外され、Transact-SQL ステートメントは 0 行を返します。
-- 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
これは CLR の null セマンティクスとは大きく異なり、null-equals-null 比較では true が返されます。
次の LINQ クエリは CLR で表されますが、データ ソースで実行されます。 CLR セマンティクスがデータ ソースで受け入れられる保証がないため、予期される動作は不確定です。
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 : {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
キー セレクター
キー セレクターは、要素からキーを抽出するために標準クエリ演算子で使用される関数です。 キー セレクター関数では、式を定数と比較できます。 式が null 定数と比較される場合、または 2 つの null 定数が比較される場合、CLR null セマンティクスが示されます。 データ ソース内の null 値を持つ 2 つの列を比較すると、ストアの null セマンティクスが表示されます。 キー セレクターは、 GroupByなどの多くのグループ化および順序付け標準クエリ演算子で見つかり、クエリ結果の順序付けまたはグループ化に使用されるキーを選択するために使用されます。
NULL オブジェクトの NULL プロパティ
Entity Framework では、null オブジェクトのプロパティは null です。 CLR で null オブジェクトのプロパティを参照しようとすると、 NullReferenceExceptionを受け取ります。 LINQ クエリに null オブジェクトのプロパティが含まれている場合、一貫性のない動作が発生する可能性があります。
たとえば、次のクエリでは、 NewProduct へのキャストがコマンド ツリー レイヤーで実行され、 Introduced プロパティが null になる可能性があります。
DateTime比較が true に評価されるように、データベースで null 比較が定義されている場合、行が含まれます。
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
Null のコレクションを集約関数に渡す
LINQ to Entities では、集計関数に IQueryable をサポートするコレクションを渡すと、集計操作がデータベースで実行されます。 メモリ内で実行されたクエリとデータベースで実行されたクエリの結果に違いがある可能性があります。 メモリ内クエリでは、一致がない場合、クエリは 0 を返します。 データベースでは、同じクエリが nullを返します。
null値が LINQ 集計関数に渡されると、例外がスローされます。 可能な null 値を受け入れるには、クエリ結果を受け取る型の型とプロパティを null 許容値型にキャストします。