对象查询(实体框架)
ObjectQuery 泛型类表示一个查询,该查询可以返回零个或零个以上类型化对象的集合。 ObjectQuery 属于包含编写和执行查询所必需的连接和元数据信息的 ObjectContext。 可以使用 new 运算符构造 ObjectQuery,并将查询字符串和对象上下文传递到该构造函数。 但是,更通用的方案是使用 ObjectContext 派生类的属性获取表示实体集的集合的 ObjectQuery 实例。 通常,通过由实体框架工具生成的类或通过 POCO 类创建 ObjectContext 的子类,且对象上下文中的属性返回作为 ObjectQuery(在 .NET Framework 版本 3.5 SP1 中)或作为 ObjectSet(在 .NET Framework 版本 4)的实体集。 在类型化实体集的上下文中,ObjectSet 类扩展 ObjectQuery 类以提供功能,例如,添加和删除对象。
默认的 ObjectQuery 提供返回指定类型的所有实体的起始查询。 通过将 LINQ to Entities 或查询生成器方法可以进一步优化此查询。
下面的示例对 Products
集合的对象上下文进行查询。
Using context As New AdventureWorksEntities
Dim products As ObjectSet(Of Product) = context.Products
Dim productsQuery = _
From product In products _
Select product
Console.WriteLine("Product Names:")
For Each product In productsQuery
Console.WriteLine(product.Name)
Next
End Using
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
IQueryable<Product> productsQuery = from product in context.Products
select product;
Console.WriteLine("Product Names:");
foreach (var prod in productsQuery)
{
Console.WriteLine(prod.Name);
}
}
查询执行
在以下情况下,将执行对象查询:
foreach (C#) 或 For Each (Visual Basic) 语句枚举对象。
一组操作(例如 ToArray、ToDictionary 或 ToList)枚举对象。
显式调用 Execute 方法。
在查询的最外面部分中指定 LINQ 运算符,例如 First 或 Any。 有关更多信息,请参见查询生成器方法(实体框架)。
注意,如果作为查询执行的结果,数据源中没有返回任何结果,则结果将包含一个空白集合而不是 null。
由实体框架 执行的查询根据数据源中的数据进行计算,且结果将不反映对象上下文中的新对象。 如果已将具有与所查询的实体相同的标识的实体附加到上下文,则将根据查询的 MergeOption 合并来自数据源的数据与上下文中已存在的数据。 若要获取缓存中的数据,请使用 ObjectStateManager 类的 GetObjectStateEntries 方法。 由于 ObjectStateManager 管理对象上下文内部的对象的状态,因此如果您需要获取已添加的、已修改的和未更改的所有对象,您可以将以下 EntityState 值的按位 OR 传递给 GetObjectStateEntries 方法:Added、Modified、Unchanged。 有关更多信息,请参见博客(可能为英文网页),它演示如何执行本地查询。
在下面的示例中,将调用 Execute 方法执行查询:
Using context As New AdventureWorksEntities()
Dim query As ObjectSet(Of Product) = context.Products
' Execute the query and get the ObjectResult.
Dim queryResult As ObjectResult(Of Product) = query.Execute(MergeOption.AppendOnly)
' Iterate through the collection of Product items.
For Each result As Product In queryResult
Console.WriteLine("{0}", result.Name)
Next
End Using
using (AdventureWorksEntities context =
new AdventureWorksEntities())
{
ObjectSet<Product> query = context.Products;
// Execute the query and get the ObjectResult.
ObjectResult<Product> queryResult = query.Execute(MergeOption.AppendOnly);
// Iterate through the collection of Product items.
foreach (Product result in queryResult)
Console.WriteLine("{0}", result.Name);
}
查询投影
对象查询经常用于返回概念模型数据作为实体对象,但也可能返回嵌套结果和匿名投影的 DbDataRecord 对象,或可返回单个值集的基元 CLR 类型。
LINQ to Entities 和 Entity SQL 均支持查询投影。 以下注意事项适用于查询投影:
某些扩展方法要求使用包含多个结果的集合作为输入。 如果 ObjectQuery 表示一个返回带单个标量结果的集合的查询,并且调用了这些扩展方法中的某个扩展方法,则将引发 ArgumentException 异常,如下面的示例中所示。
' Define a query projection that returns ' a collection with a single scalar result. Dim scalarQuery As New ObjectQuery(Of Int32)("100", context) ' Calling an extension method that requires a collection ' will result in an exception. Dim hasValues As Boolean = scalarQuery.Any()
// Define a query projection that returns // a collection with a single scalar result. ObjectQuery<Int32> scalarQuery = new ObjectQuery<Int32>("100", context); // Calling an extension method that requires a collection // will result in an exception. bool hasValues = scalarQuery.Any();
如果 ObjectQuery 可能在投影到某个基元类型时返回 null 值,则应使用该类型的可为 null 的版本。 下面的查询使用可为 null 的 DateTime,因为 SalesOrderHeader 对象的 ShipDate 属性可能返回 null 值。
Dim shipDateQuery As ObjectQuery(Of Nullable(Of DateTime)) = _ context.SalesOrderHeaders.Where("it.CustomerID = @contactId", _ New ObjectParameter("contactId", contactId)).SelectValue(Of Nullable(Of DateTime))("it.ShipDate")
ObjectQuery<Nullable<DateTime>> shipDateQuery = context.SalesOrderHeaders .Where("it.CustomerID = @contactId", new ObjectParameter("contactId", contactId)) .SelectValue<Nullable<DateTime>>("it.ShipDate");
有关更多信息,请参见可以为 null 的类型(Visual Basic 编程指南)或Nullable Types (C# Programming Guide)。
查看存储命令
在查询概念模型时,实体框架 将基于概念模型的 LINQ to Entities 和 Entity SQL 查询转换为针对数据源的等效查询。 实体框架 提供 System.Data.Objects.ObjectQuery.ToTraceString 和 System.Data.EntityClient.EntityCommand.ToTraceString 方法,允许您在运行时查看这些存储命令而无需对数据源运行跟踪。 有关更多信息,请参见如何:查看存储命令(实体框架)。
通过对象的 EntityKey 检索对象
如果知道实体的键值,则可以从数据源中检索该实体,而无需显式创建并执行对象查询。 ObjectContext 上的 GetObjectByKey 和 TryGetObjectByKey 方法将具有指定 EntityKey 的对象返回到对象上下文。 使用 GetObjectByKey 时,如果提供的 EntityKey 与现有实体不对应,则必须处理 ObjectNotFoundException。 有关更多信息,请参见如何:使用特定对象的键返回特定对象(实体框架)。