NULL 比較
データ ソースの null
値は不明な値を表します。 LINQ to Entities クエリでは、null 値をチェックして、必ず null でない有効なデータを持つ行に特定の計算または比較を行うようにすることができます。 ただし、CLR の NULL セマンティクスは、データ ソースの NULL セマンティクスとは異なる場合があります。 ほとんどのデータベースでは、3 値論理を使用して NULL 比較を処理します。 つまり、null 値との比較は true
にも false
にも評価されず、unknown
に評価されます。 これは、多くの場合は ANSI NULL の実装ですが、そうでない場合もあります。
SQL Server の既定では、NULL = 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
これは、NULL = NULL の比較が true を返す CLR の NULL セマンティクスとは大きく異なります。
次の 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 : {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
キー セレクター
"キー セレクター" とは、要素からキーを抽出するために標準クエリ演算子で使用される関数です。 キー セレクター関数では、式を定数と比較できます。 式が 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 許容値型にキャストします。