前面的Part 1-3的文章,介绍了Entity Data Model、Entity
SQL、ObjectQuery、EntityCommand、LINQ to
Entities等等及其代码演示。Part 4主要演示如何通过相关技术或Debug工具,如SQL
Server Profiler、ToTraceString 方法、eSqlBlast
工具、LINQPad工具等等,来查看生成的T-SQL脚本。Part 5
演示如何新增、更新和删除数据实体,并相应更新数据库。Part 6 演示如何处理并发更新。本篇文章Part
7 介绍对象状态管理器 ObjectStateManager 及MergeOption.NoTracking
选项的用法。
我们已经知道如何增加、更新和删除实体记录,并将更改数据库记录。Entity
Framework 通过Object Context 控制的ObjectStateManager
对象来跟踪变更,ObjectStateManager 将跟踪所有对实体对象的变更,在调用SaveChanges()
方法时,执行相应的T-SQL脚本
ObjectStateManager比LINQ to SQL中DataContext
的变更跟踪功能更先进。下面,我们详细了解如何显示有用的变更跟踪信息。
ObjectStateManager 有2个有趣的方法:
GetObjectStateEntries() – 返回给定状态下ObjectStateEntry
集合对象。
GetObjectStateEntry() – 返回给定实体的ObjectStateEntry
对象。
一个ObjectStateEntry 对象包含了一些有用的数据,根据状态不同(Added,
Modified, Deleted)有不同的变化。

在下面的示例中,首先检索特定的Product记录,修改其中3个属性,并调用GetObjectStateEntries(EntityState.Modified)
方法,返回所有更新实体的列表,并进一步遍历ObjectStateEntry集合,显示实体名称,Key/Value,初始值和当前值。
Product
product1 = context.Product.FirstOrDefault(p
=> p.ProductID == 1004);
if
(product1 != null)
{
product1.Color = "Black";
product1.StandardCost = 20;
product1.ListPrice = 25;
}
var
objectStateEntries = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
foreach
(var
entry in
objectStateEntries)
{
Console.WriteLine("{0}
- {1} - {2}",
entry.EntityKey.EntityContainerName,
entry.EntityKey.EntitySetName.ToString(),
entry.EntityKey.EntityKeyValues.First().Key
+ "
= " +
entry.EntityKey.EntityKeyValues.First().Value);
for
(int
i = 0; i < entry.OriginalValues.FieldCount;
i++)
{
Console.WriteLine("\t
{0} -> {1}", entry.OriginalValues[i],
entry.CurrentValues[i]);
}
}
AdventureWorksLTEntities
- Product - ProductID = 1004
1004 -> 1004
def -> def
abc -> abc
Black -> Black
20.0000 -> 20
25.0000 -> 25
->
->
2008-11-3 11:33:30 -> 2008-11-3
11:33:30
->
->
->
->
5b2cfc8c-8344-4431-8c2c-651358cce331
-> 5b2cfc8c-8344-4431-8c2c-651358cce331
2008-11-3 11:33:30 -> 2008-11-3
11:33:30
MergeOption.NoTracking 选项
如果仅仅检索数据,并不需要更新数据,则可以通过使用MergeOption.NoTracking
取消变更跟踪。这样,就不会使用ObjectStateManager,减少执行查询的时间,所有返回的实体将是分离的状态(detached
state)。在ASP.NET web application 或在WinForms
/ WPF Grids 控件中以只读方式显示数据时,NoTracking
是一个比较好的选择。
在使用对象服务(Object Services)和Entity SQL时,需要调用ObjectQuery
的一个重载构造函数,其中第三个参数是MergeOption 枚举。默认的行为是
AppendOnly,可以改变为 NoTracking。
var
sql = "SELECT
VALUE model FROM AdventureWorksLTEntities.Model
AS model";
var
query = new
ObjectQuery<Model>(sql,
context,
MergeOption.NoTracking);
foreach
(var
mod in
query)
Console.WriteLine("{0}
{1} {2}", mod.ModelID, mod.Name,
mod.ModifiedDate);
1
Classic Vest 2003-6-1 0:00:00
2
Cycling Cap 2001-6-1 0:00:00
3
Full-Finger Gloves 2002-6-1 0:00:00
4
Half-Finger Gloves 2002-6-1 0:00:00
5
HL Mountain Frame 2001-6-1 0:00:00
6 HL
Road Frame 1998-5-2 0:00:00
在使用LINQ to Entities 或者与Entity SQL
一起使用的CreateQuery<T> 工厂方法时,不能直接传入NoTracking
选项,你需要对整个EntitySet 设置MergeOption 选项。
var
categories = from
c in
this.context.Category
where
c.ParentCategory.Name != null
orderby
c.Name
select
c;
context.Category.MergeOption = MergeOption.NoTracking;
return
categories.ToList();