LINQ to Entities 的已知问题和注意事项
本节提供有关 LINQ to Entities 查询的已知问题的信息。
排序信息丢失
嵌套查询
不支持无符号整数
类型转换错误
不支持引用非标量闭包
排序信息丢失
如果在排序操作之后执行了任何其他操作,则不能保证这些附加操作中会保留排序结果。这些操作包括 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 列表中的列名与选择器中的列名相同时,就会发生这种情况,如下面的示例所示:
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 to Entities 查询中指定无符号整数类型。如果指定无符号整数,则在查询表达式转换过程中会引发 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’)。”[Unable to create a constant value of type 'Closure type'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.]
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);
}
}