您的位置:首页 > 其它

ADO.NET Entity Framework 深入分析, Part 7 – Change Tracking

2008-11-11 08:19 661 查看
ADO.NET Entity Framework 深入分析, Part 7 – Change Tracking

前面的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 选项的用法。

ADO.NET Entity Framework 系列文章由EntLib.com 开源论坛、小组翻译、编写。欢迎交流、分享。

本系列文章前面部分链接:
Entity Data Model (EDM) 深入分析, Part 1
Entity Data Model (EDM) 深入分析, Part 2
Entity Data Model (EDM) 深入分析, Part 3
ADO.NET Entity Framework 深入分析, Part 4 (提供示例程序下载)
ADO.NET Entity Framework 深入分析, Part 5

ADO.NET Entity Framework 深入分析, Part 6 – 处理并发(Concurrency Handling)

ObjectStateManager – 对象状态管理器
我们已经知道如何增加、更新和删除实体记录,并将更改数据库记录。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,初始值和当前值。

示例代码如下:
[align=left] Product product1 = context.Product.FirstOrDefault(p => p.ProductID == 1004);[/align]
[align=left] if (product1 != null)[/align]
[align=left] {[/align]
[align=left] product1.Color = "Black";[/align]
[align=left] product1.StandardCost = 20;[/align]
[align=left] product1.ListPrice = 25;[/align]
[align=left] }[/align]
[align=left] [/align]
[align=left] var objectStateEntries = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);[/align]
[align=left] [/align]
[align=left] foreach (var entry in objectStateEntries)[/align]
[align=left] {[/align]
[align=left] Console.WriteLine("{0} - {1} - {2}",[/align]
[align=left] entry.EntityKey.EntityContainerName,[/align]
[align=left] entry.EntityKey.EntitySetName.ToString(),[/align]
[align=left] entry.EntityKey.EntityKeyValues.First().Key + " = " +[/align]
[align=left] entry.EntityKey.EntityKeyValues.First().Value);[/align]
[align=left] [/align]
[align=left] for (int i = 0; i < entry.OriginalValues.FieldCount; i++)[/align]
[align=left] {[/align]
[align=left] Console.WriteLine("\t {0} -> {1}", entry.OriginalValues[i], entry.CurrentValues[i]);[/align]
[align=left] }[/align]
}

输出结果如下:
[align=left]AdventureWorksLTEntities - Product - ProductID = 1004[/align]
[align=left] 1004 -> 1004[/align]
[align=left] def -> def[/align]
[align=left] abc -> abc[/align]
[align=left] Black -> Black[/align]
[align=left] 20.0000 -> 20[/align]
[align=left] 25.0000 -> 25[/align]
[align=left] -> [/align]
[align=left] -> [/align]
[align=left] 2008-11-3 11:33:30 -> 2008-11-3 11:33:30[/align]
[align=left] -> [/align]
[align=left] -> [/align]
[align=left] -> [/align]
[align=left] -> [/align]
[align=left] 5b2cfc8c-8344-4431-8c2c-651358cce331 -> 5b2cfc8c-8344-4431-8c2c-651358cce331[/align]
[align=left] 2008-11-3 11:33:30 -> 2008-11-3 11:33:30[/align]

MergeOption.NoTracking 选项
如果仅仅检索数据,并不需要更新数据,则可以通过使用MergeOption.NoTracking 取消变更跟踪。这样,就不会使用ObjectStateManager,减少执行查询的时间,所有返回的实体将是分离的状态(detached state)。在ASP.NET web application 或在WinForms / WPF Grids 控件中以只读方式显示数据时,NoTracking 是一个比较好的选择。

在使用对象服务(Object Services)和Entity SQL时,需要调用ObjectQuery 的一个重载构造函数,其中第三个参数是MergeOption 枚举。默认的行为是 AppendOnly,可以改变为 NoTracking。

示例代码如下:
[align=left]var sql = "SELECT VALUE model FROM AdventureWorksLTEntities.Model AS model";[/align]
[align=left]var query = new ObjectQuery<Model>(sql, context, MergeOption.NoTracking);[/align]
[align=left]foreach (var mod in query)[/align]
[align=left] Console.WriteLine("{0} {1} {2}", mod.ModelID, mod.Name, mod.ModifiedDate);[/align]

输出结果如下:
[align=left]1 Classic Vest 2003-6-1 0:00:00[/align]
[align=left]2 Cycling Cap 2001-6-1 0:00:00[/align]
[align=left]3 Full-Finger Gloves 2002-6-1 0:00:00[/align]
[align=left]4 Half-Finger Gloves 2002-6-1 0:00:00[/align]
[align=left]5 HL Mountain Frame 2001-6-1 0:00:00[/align]
6 HL Road Frame 1998-5-2 0:00:00

在使用LINQ to Entities 或者与Entity SQL 一起使用的CreateQuery<T> 工厂方法时,不能直接传入NoTracking 选项,你需要对整个EntitySet 设置MergeOption 选项。

示例代码如下:
[align=left]var categories = from c in this.context.Category[/align]
[align=left] where c.ParentCategory.Name != null[/align]
[align=left] orderby c.Name[/align]
[align=left] select c;[/align]
[align=left] [/align]
[align=left] context.Category.MergeOption = MergeOption.NoTracking;[/align]
[align=left] [/align]
return categories.ToList();

本文由EntLib.com Blog ( http://blog.EntLib.com ) 开源博客小组编译,欢迎各位交流、分享Entity Framework / LINQ 等等相关技术。

英文链接:
http://www.scip.be/index.php?Page=ArticlesNET16#Concurrency , by Stefan Cruysberghs
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: