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