このセクションでは、LINQ to Entities クエリに関する既知の問題について説明します。
キャッシュできない LINQ クエリ
.NET Framework 4.5 以降では、LINQ to Entities クエリが自動的にキャッシュされます。 ただし、 Enumerable.Contains
演算子をメモリ内コレクションに適用する LINQ to Entities クエリは、自動的にはキャッシュされません。 また、コンパイル済みの LINQ クエリでのメモリ内コレクションのパラメーター化は許可されません。
注文情報が失われた
列を匿名型に射影すると、互換性レベル "80" に設定された SQL Server 2005 データベースに対して実行される一部のクエリで順序情報が失われます。 これは、次の例に示すように、並べ替えリスト内の列名がセレクターの列名と一致する場合に発生します。
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
// Ordering information is lost when executed against a SQL Server 2005
// database running with a compatibility level of "80".
var results = context.Contacts.SelectMany(c => c.SalesOrderHeaders)
.OrderBy(c => c.SalesOrderDetails.Count)
.Select(c => new { c.SalesOrderDetails.Count });
foreach (var result in results)
Console.WriteLine(result.Count);
}
Using context As New AdventureWorksEntities()
' Ordering information is lost when executed against a SQL Server 2005
' database running with a compatibility level of "80".
Dim results = context.Contacts.SelectMany(Function(c) c.SalesOrderHeaders) _
.OrderBy(Function(c) c.SalesOrderDetails.Count) _
.Select(Function(c) New With {c.SalesOrderDetails.Count})
For Each result In results
Console.WriteLine(result.Count)
Next
End Using
符号なし整数はサポートされていません
ENTITY Framework では符号なし整数がサポートされていないため、LINQ to Entities クエリでの符号なし整数型の指定はサポートされていません。 符号なし整数を指定すると、次の例に示すように、クエリ式の変換中に ArgumentException 例外がスローされます。 この例では、ID 48000 の注文を照会します。
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
uint s = UInt32.Parse("48000");
IQueryable<SalesOrderDetail> query = from sale in context.SalesOrderDetails
where sale.SalesOrderID == s
select sale;
// NotSupportedException exception is thrown here.
try
{
foreach (SalesOrderDetail order in query)
Console.WriteLine("SalesOrderID: " + order.SalesOrderID);
}
catch (NotSupportedException ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
}
Using context As New AdventureWorksEntities()
Dim saleId As UInteger = UInt32.Parse("48000")
Dim query = _
From sale In context.SalesOrderDetails _
Where sale.SalesOrderID = saleId _
Select sale
Try
' NotSupportedException exception is thrown here.
For Each order As SalesOrderDetail In query
Console.WriteLine("SalesOrderID: " & order.SalesOrderID)
Next
Catch ex As NotSupportedException
Console.WriteLine("Exception: " + ex.Message)
End Try
End Using
型変換エラー
Visual Basic では、プロパティが、 CByte
関数を使用して値 1 の SQL Server ビット型の列にマップされると、"算術オーバーフロー エラー" メッセージを含む SqlException がスローされます。 次の例では、AdventureWorks サンプル データベースの Product.MakeFlag
列に対してクエリを実行します。クエリ結果が反復処理されると例外がスローされます。
Using context As New AdventureWorksEntities()
Dim productsList = _
From product In context.Products _
Select CByte(product.MakeFlag)
' Throws an SqlException exception with a "Arithmetic overflow error
' for data type tinyint" message when a value of 1 is iterated over.
For Each makeFlag In productsList
Console.WriteLine(makeFlag)
Next
End Using
サポートされていないスカラー変数の参照
クエリでのエンティティなどの非スカラー変数の参照はサポートされていません。 このようなクエリを実行すると、 NotSupportedException 例外がスローされ、"unable to create a constant value of type EntityType
。 このコンテキストでは、プリミティブ型 (Int32、String、Guid など) のみがサポートされています。
注
スカラー変数のコレクションの参照がサポートされています。
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
Contact contact = context.Contacts.FirstOrDefault();
// Referencing a non-scalar closure in a query will
// throw an exception when the query is executed.
IQueryable<string> contacts = from c in context.Contacts
where c == contact
select c.LastName;
try
{
foreach (string name in contacts)
{
Console.WriteLine($"Name: ");
}
}
catch (NotSupportedException ex)
{
Console.WriteLine(ex.Message);
}
}
Using context As New AdventureWorksEntities()
Dim contact As Contact = context.Contacts.FirstOrDefault()
' Referencing a non-scalar closure in a query will
' throw an exception when the query is executed.
Dim contacts = From c In context.Contacts _
Where c.Equals(contact) _
Select c.LastName
Try
For Each name As String In contacts
Console.WriteLine("Name: ", name)
Next
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Using
入れ子になったクエリが SQL Server 2000 で失敗する可能性がある
SQL Server 2000 では、LINQ to Entities クエリは、3 つ以上のレベルの深い入れ子になった Transact-SQL クエリを生成すると失敗する可能性があります。
匿名型への射影
ObjectQuery<T>のInclude メソッドを使用して関連オブジェクトを含める最初のクエリ パスを定義し、LINQ を使用して返されたオブジェクトを匿名型に射影する場合、include メソッドで指定されたオブジェクトはクエリ結果に含まれません。
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
var resultWithoutRelatedObjects =
context.Contacts.Include("SalesOrderHeaders").Select(c => new { c }).FirstOrDefault();
if (resultWithoutRelatedObjects.c.SalesOrderHeaders.Count == 0)
{
Console.WriteLine("No orders are included.");
}
}
Using context As New AdventureWorksEntities()
Dim resultWithoutRelatedObjects = context.Contacts. _
Include("SalesOrderHeaders"). _
Select(Function(c) New With {c}).FirstOrDefault()
If resultWithoutRelatedObjects.c.SalesOrderHeaders.Count = 0 Then
Console.WriteLine("No orders are included.")
End If
End Using
関連するオブジェクトを取得するには、返された型を匿名型に射影しないでください。
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
var resultWithRelatedObjects =
context.Contacts.Include("SalesOrderHeaders").Select(c => c).FirstOrDefault();
if (resultWithRelatedObjects.SalesOrderHeaders.Count != 0)
{
Console.WriteLine("Orders are included.");
}
}
Using context As New AdventureWorksEntities()
Dim resultWithRelatedObjects = context.Contacts. _
Include("SalesOrderHeaders"). _
Select(Function(c) c).FirstOrDefault()
If resultWithRelatedObjects.SalesOrderHeaders.Count <> 0 Then
Console.WriteLine("Orders are included.")
End If
End Using