LINQ to Entities 中的已知問題和考量因素
本節提供有關 LINQ 到實體 查詢已知問題的資訊。
排序資訊遺失
巢狀查詢
不支援不帶正負號的整數
型別轉換錯誤
不支援參考非純量結束
排序資訊遺失
如果在排序運算之後執行了任何其他運算,在這些其他運算中不一定會保持排序。這包括 Select 或 Where 之類的運算,如以下範例所示:
Using AWEntities As New AdventureWorksEntities()
' In this query, the ordering is not preserved because Distinct
' is called after OrderByDescending.
Dim productsList = _
From product In AWEntities.Product _
Order By product.Name Descending _
Select product.Name _
Distinct
Console.WriteLine("The list of products:")
For Each productName In productsList
'Console.WriteLine(productName)
Next
' In this query, the ordering is preserved because
' OrderByDescending is called after Distinct.
Dim productsList2 = _
From product In AWEntities.Product _
Select product.Name _
Distinct _
Order By Name Descending
Console.WriteLine("The list of products:")
For Each productName In productsList2
Console.WriteLine(productName)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
// In this query, the ordering is not preserved because Distinct
// is called after OrderByDescending.
IQueryable<string> productsList = AWEntities.Product
.OrderByDescending(p => p.Name)
.Select(p => p.Name)
.Distinct();
Console.WriteLine("The list of products:");
foreach (string productName in productsList)
{
Console.WriteLine(productName);
}
// In this query, the ordering is preserved because
// OrderByDescending is called after Distinct.
IQueryable<string> productsList2 = AWEntities.Product
.Select(p => p.Name)
.Distinct()
.OrderByDescending(p => p);
Console.WriteLine("The list of products:");
foreach (string productName in productsList2)
{
Console.WriteLine(productName);
}
}
在針對相容性層級設定為 "80" 的 SQL Server 2005 資料庫執行的某些查詢中,將資料行投影到匿名型別將會造成排序資訊遺失。如果 order-by 清單中的資料行名稱與 selector 中的資料行名稱相符,就會發生這種情況,如以下範例所示:
Using AWEntities As New AdventureWorksEntities()
' Ordering information is lost when executed against a SQL Server 2005
' database running with a compatibility level of "80".
Dim results = AWEntities.Contact.SelectMany(Function(c) c.SalesOrderHeader) _
.OrderBy(Function(c) c.SalesOrderDetail.Count) _
.Select(Function(c) New With {c.SalesOrderDetail.Count})
For Each result In results
Console.WriteLine(result.Count)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
// Ordering information is lost when executed against a SQL Server 2005
// database running with a compatibility level of "80".
var results = AWEntities.Contact.SelectMany(c => c.SalesOrderHeader)
.OrderBy(c => c.SalesOrderDetail.Count)
.Select(c => new { c.SalesOrderDetail.Count });
foreach (var result in results)
Console.WriteLine(result.Count);
}
接受運算式當做輸入參數的 First 和 FirstOrDefault 方法不會保持排序。
Using AWEntities As New AdventureWorksEntities()
' The First() and FirstOrDefault() methods which take expressions
' as input parameters do not preserve order.
Dim orders = AWEntities.SalesOrderHeader _
.Where(Function(c) c.TotalDue = 11.039) _
.OrderByDescending(Function(c) c.SalesOrderID) _
.Select(Function(c) c)
Console.WriteLine("The ordered results:")
For Each order As SalesOrderHeader In orders
Console.WriteLine("ID: {0} Total due: {1}", order.SalesOrderID, order.TotalDue)
Next
Dim result As SalesOrderHeader = AWEntities.SalesOrderHeader _
.Where(Function(c) c.TotalDue = 11.039) _
.OrderByDescending(Function(c) c.SalesOrderID) _
.First(Function(c) c.SalesOrderID > 500)
Console.WriteLine("")
Console.WriteLine("The result returned is not the first result from the ordered list.")
Console.WriteLine("ID: {0} Total due: {1}", result.SalesOrderID, result.TotalDue)
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
// The First() and FirstOrDefault() methods which take expressions
// as input parameters do not preserve order.
var orders = AWEntities.SalesOrderHeader
.Where(c => c.TotalDue == 11.039M)
.OrderByDescending(c => c.SalesOrderID)
.Select(c => c);
Console.WriteLine("The ordered results:");
foreach (SalesOrderHeader order in orders)
Console.WriteLine("ID: {0} \t Total due: {1}", order.SalesOrderID, order.TotalDue);
SalesOrderHeader result = AWEntities.SalesOrderHeader
.Where(c => c.TotalDue == 11.039M)
.OrderByDescending(c => c.SalesOrderID)
.First(c => c.SalesOrderID > 500);
Console.WriteLine("");
Console.WriteLine("The result returned is not the first result from the ordered list.");
Console.WriteLine("ID: {0} \t Total due: {1}", result.SalesOrderID, result.TotalDue);
}
}
巢狀查詢
巢狀查詢中不會保持排序。在下列範例中,依據姓氏的排序會在呼叫第二個 Select 方法時遺失。
Using AWEntities As New AdventureWorksEntities()
Dim contacts = AWEntities.Contact _
.OrderBy(Function(x) x.LastName) _
.Select(Function(x) x) _
.Select(Function(x) x.LastName)
For Each contact In contacts
Console.WriteLine(contact)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
// Return all contacts, ordered by last name.
IQueryable<string> contacts = AWEntities.Contact
.OrderBy(x => x.LastName)
.Select(x => x)
.Select(x => x.LastName);
foreach (var c in contacts)
{
Console.WriteLine(c);
}
}
在下列範例中,在 Where 方法之前呼叫 OrderBy 方法會在此查詢轉譯成標準命令樹時產生巢狀陳述式,而且會遺失排序:
Using AWEntities As New AdventureWorksEntities()
' Return all contacts, ordered by last name. The OrderBy before
' the Where produces a nested query when translated to
' canonical command trees and the ordering by last name is lost.
Dim contacts = AWEntities.Contact _
.OrderBy(Function(x) x.LastName) _
.Where(Function(x) x.FirstName = "John") _
.Select(Function(x) x)
For Each c In contacts
Console.WriteLine(c.LastName & ", " & c.FirstName)
Next
' Return all contacts, ordered by last name.
Dim contacts2 = AWEntities.Contact _
.Where(Function(x) x.FirstName = "John") _
.OrderBy(Function(x) x.LastName) _
.Select(Function(x) x)
For Each c In contacts2
Console.WriteLine(c.LastName & ", " & c.FirstName)
Next
End Using
using (AdventureWorksEntities AWEntities = new AdventureWorksEntities())
{
// Return all contacts, ordered by last name. The OrderBy before
// the Where produces a nested query when translated to
// canonical command trees and the ordering by last name is lost.
IQueryable<Contact> contacts = AWEntities.Contact
.OrderBy(x => x.LastName)
.Where(x => x.FirstName == "John")
.Select(x => x);
foreach (var c in contacts)
{
Console.WriteLine(c.LastName + ", " + c.FirstName);
}
// Return all contacts, ordered by last name.
IQueryable<Contact> contacts2 = AWEntities.Contact
.Where(x => x.FirstName == "John")
.OrderBy(x => x.LastName)
.Select(x => x);
foreach (var c in contacts2)
{
Console.WriteLine(c.LastName + ", " + c.FirstName);
}
}
不支援不帶正負號的整數
不支援在 LINQ 到實體 查詢中指定不帶正負號的整數型別,因為 實體架構 不支援不帶正負號的整數。如果指定不帶正負號的整數,查詢運算式轉譯期間將會擲回 ArgumentException 例外狀況,如以下範例所示。此範例會查詢 ID 為 48000 的訂單。
Using AWEntities As New AdventureWorksEntities()
Dim saleId As UInteger = UInt32.Parse("48000")
Dim sales As ObjectQuery(Of SalesOrderDetail) = AWEntities.SalesOrderDetail
Dim query = _
From sale In sales _
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 AWEntities = new AdventureWorksEntities())
{
uint s = UInt32.Parse("48000");
ObjectQuery<SalesOrderDetail> sales = AWEntities.SalesOrderDetail;
IQueryable<SalesOrderDetail> query = from sale in sales
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 位元型別資料行時,將會擲回 SqlException 並且顯示「算術溢位錯誤」訊息。以下範例會查詢 AdventureWorks 範例資料庫中的 Product.MakeFlag 資料行,並且在重複處理查詢結果時擲回例外狀況。
Using AWEntities As New AdventureWorksEntities()
Dim productsList = _
From product In AWEntities.Product _
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 例外狀況,並且顯示一則訊息,表示「無法建立『結束型別』型別的常數值。在此僅支援基本型別 (『例如 Int32、String 和 Guid』)」。
Using AWEntities As New AdventureWorksEntities()
Dim contact As Contact = AWEntities.Contact.FirstOrDefault()
' Referencing a non-scalar closure in a query will
' throw an exception when the query is executed.
Dim contacts = From c In AWEntities.Contact _
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 AWEntities = new AdventureWorksEntities())
{
Contact contact = AWEntities.Contact.FirstOrDefault();
// Referencing a non-scalar closure in a query will
// throw an exception when the query is executed.
IQueryable<string> contacts = from c in AWEntities.Contact
where c == contact
select c.LastName;
try
{
foreach (string name in contacts)
{
Console.WriteLine("Name: ", name);
}
}
catch (NotSupportedException ex)
{
Console.WriteLine(ex.Message);
}
}