LINQ to Entities の既知の問題および注意点
ここでは、LINQ to Entities クエリの既知の問題について説明します。
失われた情報の収集の順序付け
サポートされていない符号なし整数
型変換エラー
非スカラー変数の参照はサポートされていません
入れ子になったクエリは、SQL Server 2000 では失敗する可能性があります
匿名型への投影
失われた情報の収集の順序付け
匿名型に列を投影すると、互換性レベルが "80" に設定された SQL Server 2005 データベースに対して実行されるクエリの一部で順序付けが失われます。 この状況は、次の例に示すように、ORDER BY リストの列名がセレクターの列名と一致する場合に発生します。
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
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);
}
サポートされていない符号なし整数
Entity Framework によって符号なし整数がサポートされていないため、LINQ to Entities クエリでの符号なし整数型の指定はサポートされていません。 次の例に示すように、符号なし整数を指定すると、クエリ式の変換時に ArgumentException 例外がスローされます。 この例では、ID 48000 を持つ注文に対してクエリを実行します。
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
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: {0}", ex.Message);
}
}
型変換エラー
Visual Basic では、CByte 関数を使用して 1 の値を持つ SQL Server の bit 型の列にプロパティがマップされると、"算術オーバーフロー エラー" というメッセージと共に 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 例外がスローされ、"型 EntityType の定数値を作成できません。 このコンテキストでサポートされるのはプリミティブ型 ('Int32、String、Guid など') だけです" というメッセージが表示されます。
注 : |
---|
スカラー変数のコレクションの参照はサポートされています。 |
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
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: ", name);
}
}
catch (NotSupportedException ex)
{
Console.WriteLine(ex.Message);
}
}
入れ子になったクエリは、SQL Server 2000 では失敗する可能性があります
SQL Server 2000 では、LINQ to Entities クエリは、3 ~ 4 レベルの深さの入れ子になった Transact-SQL クエリを生成する場合に失敗する可能性があります。
匿名型への投影
ObjectQuery に Include メソッドを使用して、関連オブジェクトを含めるように最初のクエリ パスを定義してから LINQ を使用して、返されたオブジェクトを匿名の型に投影した場合、include メソッドで指定されたオブジェクトはクエリ結果に含まれません。
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 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 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
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.");
}
}