EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态

EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态

 2013/9/10 10:06:48  心态要好  博客园  我要评论(1)
  • 摘要:本文目录查看实体当前、原始和数据库值:DbEntityEntry查看实体的某个属性值:GetValue<TValue>方法拷贝DbPropertyValues到实体:ToObject方法修改DbPropertyValues当前值:索引器克隆实体:Clone方法设置实体的值:SetValues方法克隆实体:SetValues获取和设置实体的单个属性:Property方法查询实体的属性是否被修改:IsModified方法修改导航属性重新加载实体:Reload方法读取相关联的实体和状态
  • 标签:方法 数据库 数据

本文目录

  • 查看实体当前、原始和数据库值:DbEntityEntry
  • 查看实体的某个属性值:GetValue<TValue>方法
  • 拷贝DbPropertyValues到实体:ToObject方法
  • 修改DbPropertyValues当前值:索引器
  • 克隆实体:Clone方法
  • 设置实体的值:SetValues方法
  • 克隆实体:SetValues
  • 获取和设置实体的单个属性:Property方法
  • 查询实体的属性是否被修改:IsModified方法
  • 修改导航属性
  • 重新加载实体:Reload方法
  • 读取相关联的实体和状态:DbContext.ChangeTracker.Entries方法
  • EF里如何解决更新时的冲突
  • 重写上下文的SaveChanges方法记录结果集里实体的各种增/删/改
  • 本源源码和系列文章导航

文章开始前建议大家为了更好的记忆最好自己实现文中的所有方法。如果非要直接运行我的demo,必要的时候需要恢复下数据库数据,否则找不到记录。

之前的章节已经演示了context.Entry方法可以拿到实体的状态(EntityState),我们看一个方法:

        /// <summary>
        /// 单个实体的状态
        /// </summary>
        private static void PrintState()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var canyon = (from d in context.Destinations
                              where d.Name == "Grand Canyon"
                              select d).Single();
                DbEntityEntry<DbContexts.Model.Destination> entry = context.Entry(canyon);
                Console.WriteLine("Before Edit:{0}", entry.State);   //Unchaged

                canyon.TravelWarnings = "Take a lot of Water!";
                DbEntityEntry<DbContexts.Model.Destination> entrys = context.Entry(canyon);

Console.WriteLine(
"After Edit:{0}", entrys.State); //Modified } }

context.Entry方法有两个重载,分别返回泛型DbEntityEntry<TEntity>和非泛型的DbEntityEntry,它们都可以监测到实体的状态,并且通过DbEntityEntry还可以操作实体的当前值、原始值和数据库值。他们分别是:

  • 当前值(Current Value):当前设置实体属性的值;
  • 原始值(Original Value):刚被数据库上下文跟踪到时的值;
  • 数据库值(Database Value):存在数据库里的值

来看一个例子

        /// <summary>
        /// 打印实体当前、原始和数据库值
        /// </summary>
        private static void PrintLodgingInfo()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var hotel = (from d in context.Lodgings
                             where d.Name == "Grand Hotel"
                             select d).Single();
                hotel.Name = "Super Grand Hotel";
                context.Database.ExecuteSqlCommand(@"UPDATE Lodgings SET Name = 'Not-So-Grand Hotel' WHERE Name = 'Grand Hotel'");
                PrintChangeTrackingInfo(context, hotel);
            }
        }
        private static void PrintChangeTrackingInfo(DbContexts.DataAccess.BreakAwayContext context, DbContexts.Model.Lodging entity)
        {
            var entry = context.Entry(entity);
            Console.WriteLine(entry.Entity.Name);
            Console.WriteLine("State: {0}", entry.State);

            Console.WriteLine("\nCurrent Values:");
            PrintPropertyValues(entry.CurrentValues);

            Console.WriteLine("\nOriginal Values:");
            PrintPropertyValues(entry.OriginalValues);

            Console.WriteLine("\nDatabase Values:");
            PrintPropertyValues(entry.GetDatabaseValues());
        }
        private static void PrintPropertyValues(DbPropertyValues values)
        {
            foreach (var propertyName in values.PropertyNames)
            {
                Console.WriteLine(" - {0}: {1}", propertyName, values[propertyName]);
            }
        }

方法分析:先从数据库取出一个实体,然后修改其Name属性,这个时候当前值(Current)和原始值(Original)都有了,分别是:修改后的值(还没提交,在内存中)和从库里取出来时实体的值。再使用Database.ExecuteSqlCommand执行了一段修改此对象在数据库中的值,这个时候数据库值(Database)也有了变化,这个实体的三个值都不相同了。还没看到打印结果,在执行entry.GetDatabaseValues()方法时报了一个EntitySqlException错:

找不到类型DbContexts.DataAccess.Lodging,项目的Lodging实体明明在DbContexts.Model.Lodging命名空间下,反复检查代码没发现任何问题,报这个错真是很疑惑。最后通过搜索引擎才知道这是EF4.1版本的一个bug,解决办法:修改实体和上下文到一个命名空间,或者使用EF4.3 release。看看本书作者Julie Lerman在msdn论坛上关于此bug的回复

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" alt="" />

换成4.3版本的EF问题就立马解决了(源码的libs目录下提供了EF4.3)。看下打印的结果:

结果分析:当前值为方法里修改的值、原始值是从数据库取出未做任何操作的值、数据库值是此时数据库里的值。当然新添加的实体不会有原始值和数据库值、删除的实体也不会有当前值,我们利用EntityState完善下方法:

        private static void PrintChangeTrackingInfo(DbContexts.DataAccess.BreakAwayContext context, DbContexts.Model.Lodging entity)
        {
            var entry = context.Entry(entity);
            Console.WriteLine(entry.Entity.Name);
            Console.WriteLine("State: {0}", entry.State);

            if (entry.State != EntityState.Deleted)   //标记删除的实体不会有当前值
            {
                Console.WriteLine("\nCurrent Values:");
                PrintPropertyValues(entry.CurrentValues);
            }
            if (entry.State != EntityState.Added)   //新添加的时候不会有原始值和数据库值
            {
                Console.WriteLine("\nOriginal Values:");
                PrintPropertyValues(entry.OriginalValues);
                Console.WriteLine("\nDatabase Values:");
                PrintPropertyValues(entry.GetDatabaseValues());
            }
        }

为了测试,我们重写下PrintLodgingInfo方法:

        /// <summary>
        /// 测试打印添加和删除时实体当前、原始和数据库值
        /// </summary>
        private static void PrintLodgingInfoAddAndDelete()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var hotel = (from d in context.Lodgings
                             where d.Name == "Grand Hotel"
                             select d).Single();
                PrintChangeTrackingInfo(context, hotel);   //默认

                var davesDump = (from d in context.Lodgings
                                 where d.Name == "Dave's Dump"
                                 select d).Single();
                context.Lodgings.Remove(davesDump);
                PrintChangeTrackingInfo(context, davesDump);   //测试删除实体

                var newMotel = new DbContexts.Model.Lodging { Name = "New Motel" };
                context.Lodgings.Add(newMotel);
                PrintChangeTrackingInfo(context, newMotel);  //测试新添加实体
            }
        }

当然上面打印实体类型的方法并不通用,我们修改第二个参数为object类型:

        /// <summary>
        /// 通用的打印实体方法
        /// </summary>
        private static void PrintChangeTrackingInfo(DbContexts.DataAccess.BreakAwayContext context, object entity)
        {
            var entry = context.Entry(entity);
            Console.WriteLine("Type:{0}", entry.Entity.GetType());   //打印实体类型
            Console.WriteLine("State: {0}", entry.State);

            if (entry.State != EntityState.Deleted)   //标记删除的实体不会有当前值
            {
                Console.WriteLine("\nCurrent Values:");
                PrintPropertyValues(entry.CurrentValues);
            }
            if (entry.State != EntityState.Added)   //新添加的时候不会有原始值和数据库值
            {
                Console.WriteLine("\nOriginal Values:");
                PrintPropertyValues(entry.OriginalValues);
                Console.WriteLine("\nDatabase Values:");
                PrintPropertyValues(entry.GetDatabaseValues());
            }
        }

看看打印结果:

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" alt="" />

之前打印实体的各种属性都是通过遍历的形式(PrintPropertyValues方法)打印出来,如果仅取某个字段当然没必要这么麻烦,可以使用GetValue<TValue>:

        /// <summary>
        /// 打印实体单个属性
        /// </summary>
        private static void PrintOriginalName()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var hotel = (from d in context.Lodgings
                             where d.Name == "Grand Hotel"
                             select d).Single();
                hotel.Name = "Super Grand Hotel";
                string originalName = context.Entry(hotel).OriginalValues.GetValue<string>("Name");

                Console.WriteLine("Current Name: {0}", hotel.Name);  //Super Grand Hotel
                Console.WriteLine("Original Name: {0}", originalName);  //Grand Hotel
            }
        }

拷贝DbPropertyValues到实体:ToObject方法

        /// <summary>
        /// 拷贝DbPropertyValues到实体:ToObject方法
        /// </summary>
        private static void TestPrintDestination()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var reef = (from d in context.Destinations
                            where d.Name == "Great Barrier Reef"
                            select d).Single();
                reef.TravelWarnings = "Watch out for sharks!";
                Console.WriteLine("Current Values");
                PrintDestination(reef);

                Console.WriteLine("\nDatabase Values");
                DbPropertyValues dbValues = context.Entry(reef).GetDatabaseValues();
                PrintDestination((DbContexts.Model.Destination)dbValues.ToObject());  //ToObject方法创建Destination实例
            }
        }
        private static void PrintDestination(DbContexts.Model.Destination destination)
        {
            Console.WriteLine("-- {0}, {1} --", destination.Name, destination.Country);
            Console.WriteLine(destination.Description);
            if (destination.TravelWarnings != null)
            {
                Console.WriteLine("WARNINGS!: {0}", destination.TravelWarnings);
            }
        }

方法分析:从Destination表里取出Name为Great Barrier Reef的实体并修改其TravelWarnings字段,然后调用PrintDestination方法打印当前实体的各属性,再查出此实体在数据库里的值,并且通过ToObject方法把数据库取出来的这个对象也转换成了实体对象。这么转有什么好处呢?这个通过ToObject转换的Destination实例不会被数据库上下文追踪,所以对其做的任何改变都不会提交数据库。看看打印结果:

修改DbPropertyValues当前值:

调用上下文的Entry方法,传入要操作的实体对象,再打点就可以拿到实体的当前值(CurrentValues)、原始值(OriginalValues)、数据库值(GetDatabaseValues()),返回类型是DbPropertyValues,直接遍历就可以输出实体的所有属性。当然DbPropertyValues并不是只读的。写个方法修改试试:

        /// <summary>
        /// 修改DbPropertyValues当前值
        /// </summary>
        private static void ChangeCurrentValue()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var hotel = (from d in context.Lodgings
                             where d.Name == "Grand Hotel"
                             select d).Single();
                context.Entry(hotel).CurrentValues["Name"] = "Hotel Pretentious";
                Console.WriteLine("Property Value: {0}", hotel.Name);
                Console.WriteLine("State: {0}", context.Entry(hotel).State);  //Modified
            }
        }

类似于索引器的方式赋值即可,赋值后实体的状态已经是Modified了,显然已经被上下文追踪到了,这个时候调用上下文的SaveChanges方法将会提交到数据库。那么如果只是想打印和修改实体状态以供查看,并不像被提交到数据库怎么办呢?


最好的办法就是克隆,先克隆实体然后操作克隆之后的实体:

        /// <summary>
        /// 克隆实体:Clone
        /// </summary>
        private static void CloneCurrentValues()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var hotel = (from d in context.Lodgings
                             where d.Name == "Grand Hotel"
                             select d).Single();
                var values = context.Entry(hotel).CurrentValues.Clone();  //Clone方法
                values["Name"] = "Simple Hotel";
                Console.WriteLine("Property Value: {0}", hotel.Name);
                Console.WriteLine("State: {0}", context.Entry(hotel).State);  //Unchanged
            }
        }

设置实体的值:SetValues方法

当然实体的当前值、原始值和数据库值都是可以相互复制的:

        /// <summary>
        /// 设置实体的值:SetValues方法
        /// </summary>
        private static void UndoEdits()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var canyon = (from d in context.Destinations
                              where d.Name == "Grand Canyon"
                              select d).Single();
                canyon.Name = "Bigger & Better Canyon";

                var entry = context.Entry(canyon);
                entry.CurrentValues.SetValues(entry.OriginalValues);
                entry.State = EntityState.Unchanged;  //标记未修改

                Console.WriteLine("Name: {0}", canyon.Name); //Grand Canyon
            }
        }

上面的方法演示了拷贝原始值到当前值,最终保存的是当前值。很方便,不需要挨个赋值。

我们看看如何使用SetValues方法实现之前说的克隆实体:

        /// <summary>
        /// 克隆实体:SetValues
        /// </summary>
        private static void CreateDavesCampsite()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var davesDump = (from d in context.Lodgings
                                 where d.Name == "Dave's Dump"
                                 select d).Single();
                var clone = new DbContexts.Model.Lodging();
                context.Lodgings.Add(clone);

                context.Entry(clone).CurrentValues.SetValues(davesDump);  //克隆davesDump的值到新对象clone里
                clone.Name = "Dave's Camp";  //修改Name属性
                context.SaveChanges();  //最后提交修改

                Console.WriteLine("Name: {0}", clone.Name);  //Dave's Camp
                Console.WriteLine("Miles: {0}", clone.MilesFromNearestAirport);  //32.65
                Console.WriteLine("Contact Id: {0}", clone.PrimaryContactId);  //1
            }
        }
exec sp_executesql N'insert [dbo].[Lodgings]([Name], [Owner], [MilesFromNearestAirport], [destination_id], [PrimaryContactId], [SecondaryContactId], [Entertainment], [Activities], [MaxPersonsPerRoom], [PrivateRoomsAvailable], [Discriminator])
values (@0, null, @1, @2, @3, null, null, null, null, null, @4)
select [LodgingId]
from [dbo].[Lodgings]
where @@ROWCOUNT > 0 and [LodgingId] = scope_identity()',N'@0 nvarchar(200),@1 decimal(18,2),@2 int,@3 int,@4 nvarchar(128)',@0=N'Dave''s Camp',@1=32.65,@2=1,@3=1,@4=N'Lodging'

很明显实体已经被克隆了。

获取和设置实体的单个属性:Property方法

        /// <summary>
        /// 获取和设置实体的单个属性:Property方法
        /// </summary>
        private static void WorkingWithPropertyMethod()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var davesDump = (from d in context.Lodgings
                                 where d.Name == "Dave's Dump"
                                 select d).Single();
                var entry = context.Entry(davesDump);
                entry.Property(d => d.Name).CurrentValue = "Dave's Bargain Bungalows";  //设置Name属性

                Console.WriteLine("Current Value: {0}", entry.Property(d => d.Name).CurrentValue);  //Dave's Bargain Bungalows
                Console.WriteLine("Original Value: {0}", entry.Property(d => d.Name).OriginalValue);  //Dave's Dump
                Console.WriteLine("Modified?: {0}", entry.Property(d => d.Name).IsModified);   //True
            }
        }

同样可以查询出实体的哪些属性被修改了:IsModified方法

        /// <summary>
        /// 查询实体被修改字段:IsModified方法
        /// </summary>
        private static void FindModifiedProperties()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var canyon = (from d in context.Destinations
                              where d.Name == "Grand Canyon"
                              select d).Single();
                canyon.Name = "Super-Size Canyon";
                canyon.TravelWarnings = "Bigger than your brain can handle!!!";
                var entry = context.Entry(canyon);
                var propertyNames = entry.CurrentValues.PropertyNames;  //获取所有的Name列

                IEnumerable<string> modifiedProperties = from name in propertyNames
                                                         where entry.Property(name).IsModified
                                                         select name;
                foreach (var propertyName in modifiedProperties)
                {
                    Console.WriteLine(propertyName);  //Name、TravelWarnings
                }
            }
        }

前面的章节已经讲解了如何查询一对一、一对多等关系的导航属性了,还不了解的点这里。现在讲讲如何修改导航属性:

        /// <summary>
        /// 修改导航属性(Reference):CurrentValue方法
        /// </summary>
        private static void WorkingWithReferenceMethod()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var davesDump = (from d in context.Lodgings
                                 where d.Name == "Dave's Dump"
                                 select d).Single();
                var entry = context.Entry(davesDump);
                entry.Reference(l => l.Destination).Load();   //显示加载

                var canyon = davesDump.Destination;
                Console.WriteLine("Current Value After Load: {0}", entry.Reference(d => d.Destination).CurrentValue.Name);

                var reef = (from d in context.Destinations
                            where d.Name == "Great Barrier Reef"
                            select d).Single();
                entry.Reference(d => d.Destination).CurrentValue = reef;   //修改
                Console.WriteLine("Current Value After Change: {0}", davesDump.Destination.Name);
            }
        }

打印结果:
Current Value After Load: Grand Canyon
Current Value After Change: Great Barrier Reef

注:上面的方法并没有调用上下文的SaveChanges方法,故程序跑完数据也不会保存到数据库,本文所有方法仅作演示都未提交数据库。

有Reference找单个属性的,那么自然也有Collection找集合属性的:

        /// <summary>
        /// 修改导航属性(Collection):CurrentValue方法
        /// </summary>
        private static void WorkingWithCollectionMethod()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var res = (from r in context.Reservations
                           where r.Trip.Description == "Trip from the database"
                           select r).Single();
                var entry = context.Entry(res);
                entry.Collection(r => r.Payments).Load();
                Console.WriteLine("Payments Before Add: {0}", entry.Collection(r => r.Payments).CurrentValue.Count);

                var payment = new DbContexts.Model.Payment { Amount = 245 };
                context.Payments.Add(payment);
                entry.Collection(r => r.Payments).CurrentValue.Add(payment);  //修改
                Console.WriteLine("Payments After Add: {0}", entry.Collection(r => r.Payments).CurrentValue.Count);
            }
        }

打印结果:
Payments Before Add: 1
Payments After Add: 2

我们从数据库取出实体加载到内存中,可能并不立马就展示给用户看。在进行一系列的排序、筛选等操作再展示出来。但是怎么确定展示的时候这些实体没有被修改过呢?我们可以使用Reload方法重新加载:

        /// <summary>
        /// 取当前最新的数据库值:Reload方法
        /// </summary>
        private static void ReloadLodging()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var hotel = (from d in context.Lodgings
                             where d.Name == "Grand Hotel"
                             select d).Single();  //取出实体
                context.Database.ExecuteSqlCommand(@"UPDATE dbo.Lodgings SET Name = 'Le Grand Hotel' WHERE Name = 'Grand Hotel'");   //立马修改实体值(这个时候数据库中的值已改变,但是取出来放在内存中的值并没改变)
                Console.WriteLine("Name Before Reload: {0}", hotel.Name);
                Console.WriteLine("State Before Reload: {0}", context.Entry(hotel).State);

                context.Entry(hotel).Reload();
                Console.WriteLine("Name After Reload: {0}", hotel.Name);
                Console.WriteLine("State After Reload: {0}", context.Entry(hotel).State);
            }
        }

打印结果:
Name Before Reload: Grand Hotel
State Before Reload: Unchanged
Name After Reload: Le Grand Hotel
State After Reload: Unchanged

可以看出Reload方法已经帮我们重新取出了数据库中的最新值。来看看Reload方法生成的sql:

SELECT 
[Extent1].[Discriminator] AS [Discriminator], 
[Extent1].[LodgingId] AS [LodgingId], 
[Extent1].[Name] AS [Name], 
[Extent1].[Owner] AS [Owner], 
[Extent1].[MilesFromNearestAirport] AS [MilesFromNearestAirport], 
[Extent1].[destination_id] AS [destination_id], 
[Extent1].[PrimaryContactId] AS [PrimaryContactId], 
[Extent1].[SecondaryContactId] AS [SecondaryContactId], 
[Extent1].[Entertainment] AS [Entertainment], 
[Extent1].[Activities] AS [Activities], 
[Extent1].[MaxPersonsPerRoom] AS [MaxPersonsPerRoom], 
[Extent1].[PrivateRoomsAvailable] AS [PrivateRoomsAvailable]
FROM [dbo].[Lodgings] AS [Extent1]
WHERE ([Extent1].[Discriminator] IN ('Resort','Hostel','Lodging')) AND ([Extent1].[LodgingId] = 1)

当然Reload方法也会保存内存中修改的数据,这个并不会冲突。在方法里的linq查询后面加上:hotel.Name = "A New Name"; 打印结果就是这样的了:
Name Before Reload: A New Name
State Before Reload: Modified
Name After Reload: Le Grand Hotel
State After Reload: Unchanged

注意,代码里修改的Name已经显示了,并且标记实体状态为Modified了,Modified会在调用上下文的SaveChanges方法的时候提交到数据库。这个过程是这样的:

加载实体到内存中 - 在内存中对实体的某个属性进行修改 - 使用ExecuteSqlCommand方法执行sql修改数据库里该实体的值 - 调用Reload取出数据库里本实体的最新值 - 调用SaveChanges方法的话,在内存中对实体的修改也会被提交到数据库

之前我们操作了单个实体,现在看看如何读取关联实体和状态。使用DbContext.ChangeTracker.Entries方法:

     /// <summary>
        /// 读取相关联的实体和状态:DbContext.ChangeTracker.Entries方法
        /// </summary>
        private static void PrintChangeTrackerEntries()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var res = (from r in context.Reservations
                           where r.Trip.Description == "Trip from the database"
                           select r).Single();
                context.Entry(res).Collection(r => r.Payments).Load();
res.Payments.Add(
new DbContexts.Model.Payment { Amount = 245 }); var entries = context.ChangeTracker.Entries(); foreach (var entry in entries) { Console.WriteLine("Entity Type: {0}", entry.Entity.GetType()); Console.WriteLine(" - State: {0}", entry.State); } } }

添加了一个从表实体,并读取所有关联实体和其状态,打印结果:
Entity Type: DbContexts.Model.Payment
 - State: Added
Entity Type: DbContexts.Model.Reservation
 - State: Unchanged
Entity Type: DbContexts.Model.Payment
 - State: Unchanged

EF里如何解决更新数据时的冲突

正常根据实体的主键修改实体的时候,EF是不会判断数据修改之前有没有被别的人修改过,但是如果做了并发控制,EF在更新某条记录的时候才会抛错。这个系列文章的demo里有两个实体做了并发控制:Person类的SocialSecurityNumber字段被标记了ConcurrencyCheck;Trip类的RowVersion字段被标记了Timestamp。我们来写一个触发DbUpdateConcurrencyException异常的方法并处理这个异常:

        /// <summary>
        /// 修改实体
        /// </summary>
        private static void ConcurrencyDemo()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var trip = (from t in context.Trip.Include(t => t.Destination)
                            where t.Description == "Trip from the database"
                            select t).Single();
                trip.Description = "Getaway in Vermont";
                context.Database.ExecuteSqlCommand(@"UPDATE dbo.Trips SET CostUSD = 400 WHERE Description = 'Trip from the database'");
                SaveWithConcurrencyResolution(context);
            }
        }
        /// <summary>
        /// 尝试保存
        /// </summary>
        private static void SaveWithConcurrencyResolution(DbContexts.DataAccess.BreakAwayContext context)
        {
            try
            {
                context.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                ResolveConcurrencyConflicts(ex);
                SaveWithConcurrencyResolution(context);
            }
        }

方法分析:取出实体 - 修改实体Description属性(此时实体状态为Modified)- 使用ExecuteSqlCommand执行sql修改了CostUSD和Description字段(修改后时间戳已经不同了,PS:使用ExecuteSqlCommand执行sql不需要调用SaveChanges方法)- 调用上下文的SaveChanges方法保存之前被标记为Modified的实体,这个时候就会报一个DbUpdateConcurrencyException的异常,因为时间戳列已经找不到了,这个更新的where条件根本找不到记录了。有时间戳的列更新都是双条件,时间戳详细用法点这里了解。

我们尝试写个方法解决这个冲突:

        /// <summary>
        /// 解决冲突
        /// </summary>
        private static void ResolveConcurrencyConflicts(DbUpdateConcurrencyException ex)
        {
            foreach (var entry in ex.Entries)
            {
                Console.WriteLine("Concurrency conflict found for {0}", entry.Entity.GetType());

                Console.WriteLine("\nYou are trying to save the following values:");
                PrintPropertyValues(entry.CurrentValues);  //用户修改的值

                Console.WriteLine("\nThe values before you started editing were:");
                PrintPropertyValues(entry.OriginalValues);  //从库里取出来时的值

                var databaseValues = entry.GetDatabaseValues();  //即时数据库的值
                Console.WriteLine("\nAnother user has saved the following values:");
                PrintPropertyValues(databaseValues);

                Console.WriteLine("[S]ave your values, [D]iscard you changes or [M]erge?");
                var action = Console.ReadKey().KeyChar.ToString().ToUpper(); //读取用户输入的字母
                switch (action)
                {
                    case "S":
                        entry.OriginalValues.SetValues(databaseValues);  //拷贝数据库值到当前值(恢复时间戳)
                        break;
                    case "D":
                        entry.Reload();  //重新加载
                        break;
                    case "M":
                        var mergedValues = MergeValues(entry.OriginalValues, entry.CurrentValues, databaseValues);//合并
                        entry.OriginalValues.SetValues(databaseValues);  //拷贝数据库值到当前值(恢复时间戳)
                        entry.CurrentValues.SetValues(mergedValues);     //拷贝合并后的值到当前值,最终保存的是当前值
                        break;
                    default:
                        throw new ArgumentException("Invalid option");
                }
            }
        }

捕获到异常后告知用户要修改实体的原始值(用户修改前从数据库取出来的值)、现在的值(用户修改的值)、数据库里的值(此时数据库里的值,这个值已被修改,不是用户修改前取出来的值了),打印出来的结果显示已经有人修改了这条记录了。最后是问用户是否保存修改。分别是保存、放弃、合并修改。

用户输入"S"表示“保存”,case语句块里执行的操作是拷贝数据库值到原始值,这里该有疑惑了,调用SaveChanges方法保存的也是currentValues当前值,跟databaseValues数据库值还有OriginalValues原始值没有任何关系啊。其实这里这么操作的原因是恢复一下时间戳的值,之前说过timestamp的列更新条件是两个,任何一个不对都更新不了。看看sql:

exec sp_executesql N'update [dbo].[Trips]
set [Description] = @0, [CostUSD] = @1
where (([Identifier] = @2) and ([RowVersion] = @3))
select [RowVersion]
from [dbo].[Trips]
where @@ROWCOUNT > 0 and [Identifier] = @2',N'@0 nvarchar(max) ,@1 decimal(18,2),@2 uniqueidentifier,@3 binary(8)',@0=N'Getaway in Vermont',@1=1000.00,@2='CF2E6BD3-7393-440C-941A-
9124C61CE04A',@3=0x00000000000007D2

结果只保存了自己的修改:

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" alt="" />

用户输入“D”表示“放弃”,case语句块里执行的是Reload方法,这个方法之前已经介绍过了,是重新加载数据库里的最新值(Latest Value)。恢复下数据库数据再执行下方法,看看sql:

SELECT 
[Extent1].[Identifier] AS [Identifier], 
[Extent1].[StartDate] AS [StartDate], 
[Extent1].[EndDate] AS [EndDate], 
[Extent1].[Description] AS [Description], 
[Extent1].[CostUSD] AS [CostUSD], 
[Extent1].[RowVersion] AS [RowVersion], 
[Extent1].[DestinationId] AS [DestinationId]
FROM [dbo].[Trips] AS [Extent1]
WHERE [Extent1].[Identifier] = cast('cf2e6bd3-7393-440c-941a-9124c61ce04a' as uniqueidentifier)

取了下数据库里该实体最新的值(使用ExecuteSqlCommand更新后的值),没有其他任何更新语句,就是放弃本次修改的意思,但是之前ExecuteSqlCommand方法执行的修改是有效的,看看结果:

上面的“保存修改”和“放弃修改”都是最能达到一般的效果,如果让用户修改的和ExecuteSqlCommand的修改同时生效呢,我们选择M,意为合并。看看合并方法:

        /// <summary>
        /// 合并
        /// </summary>
        private static DbPropertyValues MergeValues(DbPropertyValues original, DbPropertyValues current, DbPropertyValues database)
        {
            var result = original.Clone();  //拷贝原始值并存放合并后的值
            foreach (var propertyName in original.PropertyNames)  //遍历原始值的所有列
            {
                if (original[propertyName] is DbPropertyValues)  //判断当前列是否复杂类型(很少)
                {
                    var mergedComplexValues =
                        MergeValues((DbPropertyValues)original[propertyName],
                        (DbPropertyValues)current[propertyName],
                        (DbPropertyValues)database[propertyName]);   //是复杂类型的话就使用递归合并复杂类型的值
                    ((DbPropertyValues)result[propertyName]).SetValues(mergedComplexValues);
                }
                else  //是普通里的话就和当前值、数据库值、原始值各种对比。修改了就赋值
                {
                    if (!object.Equals(current[propertyName], original[propertyName]))
                        result[propertyName] = current[propertyName];
                    else if (!object.Equals(database[propertyName], original[propertyName]))
                        result[propertyName] = database[propertyName];
                }
            }
            return result;
        }

看看sql:

exec sp_executesql N'update [dbo].[Trips]
set [Description] = @0, [CostUSD] = @1
where (([Identifier] = @2) and ([RowVersion] = @3))
select [RowVersion]
from [dbo].[Trips]
where @@ROWCOUNT > 0 and [Identifier] = @2',N'@0 nvarchar(max) ,@1 decimal(18,2),@2 uniqueidentifier,@3 binary(8)',@0=N'Getaway in Vermont',@1=400.00,@2='CF2E6BD3-7393-440C-941A-9124C61CE04A',@3=0x00000000000007DC

看看结果:

dos+xXwY8O+yMUAB1FOEwEeRPL0KxApLO/wvN332x/u1pMwHJIZ4VkcO8uwSBc/ZTYmS3PvVGbPTDLNTVvBGvPNVyEAJ0RpklBz1GGAff1xJHJRfr9cnqz5So7dbnfz/VauOXEg4tg5hleHNUdu+xWivNxqbrFcR+C0EGo53C3XSBHwIo2KzTDAgEyHcRN9nBbi0sbWkFN4u923m1vX3cpIQ6YTT7s/do7hpUBX3JSRqL2Tkin2a26AAbDNXlA3bM4Wy/ViOTMRMp2ZiRiH/ZqzKxByF2GT9uKYCPBAkidrvpIjXnNrx0RAVbW2ccWWjT3KMKvFiGopV3gQ4V8+ldkDnharCJxmmZ6h6MyRtaPm5aL/Prgrm1PO4b3ZLKPmZRiImpeRtPgi6O4CAwCUMSb+1A1fhLFsHq7aHMPzdtdfbzbuVvr00mTeVnA/SqDPj8BwSJc5FaZj9bSYntGU6MyJn8qsAT+flsfApVkumx+P01c+4Hm7L9ff1hs380ryBnj8uTgGPprlsvn3cfrKBzzP+/zl63rtZl5J3gAPj08KaWDref98vl6tN5lXkjfATJmy4xpslaVmrutmXUIeDf5Spuy4BqO7iUJKmM/nmdeQQyjNpQilOSmU5lKE0pwUSnMpQmlOCqW5FKE0J4XSXIpQmpNCaS5FKM1JQTXXaxTD/4RQaNjygHG9UKr30ivoYP6Ig10rFWvjNAl62XilmrMMAJKzoxG+dYs8FVtYPNc/pyCa6zWKwM6lEUN02po7DEZnRyjmtTVnGVAwdD+nZYDWDcg3OiNZCxf7LP/cwtdcRwPZhjGuF8gy8p/atRLdCJl9sVgbM9MzrhfIsrNrJd2K7KA0j08W37WfZFwvlOo1g8QEngS9RpFsw12dXHB10nDdGtcLJV0r+XlI/SQhjdKtOzYq9ImM9+WaI5UTojpauDnFtrDZnuufX0B8xbIhST27Ohid0L/XKGqGrnUno7uOxjkTT9kFp7lQGV0dYpIEq1yokw0f1wu+ELs6hBdkwqKbhLTT19vn6FIRFUOuxZaY6Ujkn19wmgtWdjBzjNHNoBdOcPiQHBbF2nhiGbo1rhf8WfT1JHiGHIWnA685thf5iieb6EisUxrOXfADORT1Us3RLTPgoVj4ozUXf8DxdEcOUP69qtcoal1/b7NrJd3q6lpX7jkiahOYSqS5iWUUa11G0JxDHjUnlveHn63cNwQdEv8uRd/VmEHS2HFdK5ETpNfQNUOPvOeJvYjvSck0N+rqzHueUGcSzUnPVmnUC/aPvZpL9k3AFPDGviGCugMT3s3DM3FiGcTBCl63ww+xyH7JvIfJPCfyXzoSao47Srg6E2lO/g0hdhqO99U1l+i3j4jo39ZvJRlA/Dh4c1C/CUuRmeb4r4e3CKU5KdTfvlKE0pwUSnMpQmlOCqW5FKE0JwXMlSk7rv0PIb3MFaUJqBEAAAAASUVORK5CYII=" alt="" />

用户修改和ExecuteSqlCommand都保存上了。

最后讲一个更实用的东西:重写上下文的SaveChanges方法记录结果集里实体的各种增/删/改。
先到BreakAwayContext类里添加一个属性标识使用数据库上下文的SaveChanges方法还是使用自定义的SaveChanges方法:public bool LogChangesDuringSave { get; set; }

来看一个方法:

        /// <summary>
        /// 记录结果集的各种:增 / 删 /改
        /// </summary>
        private static void TestSaveLogging()
        {
            using (var context = new DbContexts.DataAccess.BreakAwayContext())
            {
                var canyon = (from d in context.Destinations
                              where d.Name == "Grand Canyon"
                              select d).Single();//加载主表数据

                context.Entry(canyon).Collection(d => d.Lodgings).Load();//显示加载出从表相关数据
                canyon.TravelWarnings = "Take a hat!";//修改主表字段
                context.Lodgings.Remove(canyon.Lodgings.First());//删除相关联从表的第一条数据
                context.Destinations.Add(new DbContexts.Model.Destination { Name = "Seattle, WA" });//添加一条主表数据
                context.LogChangesDuringSave = true;  //设置标识,使用自定义的SaveChanges方法
                context.SaveChanges();
            }
        }

增加、修改、caozuo.html" target="_blank">删除操作等都有。运行这个方法前需要在BreakAwayContext类里添加记录的帮助类方法:

        /// <summary>
        /// 记录帮助类方法
        /// </summary>
        private void PrintPropertyValues(DbPropertyValues values, IEnumerable<string> propertiesToPrint, int indent = 1)
        {
            foreach (var propertyName in propertiesToPrint)
            {
                var value = values[propertyName];
                if (value is DbPropertyValues)
                {
                    Console.WriteLine("{0}- Complex Property: {1}", string.Empty.PadLeft(indent), propertyName);
                    var complexPropertyValues = (DbPropertyValues)value;
                    PrintPropertyValues(complexPropertyValues, complexPropertyValues.PropertyNames, indent + 1);
                }
                else
                {
                    Console.WriteLine("{0}- {1}: {2}", string.Empty.PadLeft(indent), propertyName, values[propertyName]);
                }
            }
        }
        private IEnumerable<string> GetKeyPropertyNames(object entity)
        {
            var objectContext = ((IObjectContextAdapter)this).ObjectContext;
            return objectContext.ObjectStateManager.GetObjectStateEntry(entity).EntityKey.EntityKeyValues.Select(k => k.Key);
        }

再在BreakAwayContext类里重写下上下文的SaveChanges方法:

        /// <summary>
        /// 重写SaveChanges方法
        /// </summary>
        public override int SaveChanges()
        {
            if (LogChangesDuringSave)  //根据表示判断用重写的SaveChanges方法,还是普通的上下文SaveChanges方法
            {
                var entries = from e in this.ChangeTracker.Entries()
                              where e.State != EntityState.Unchanged
                              select e;   //过滤所有修改了的实体,包括:增加 / 修改 / 删除
                foreach (var entry in entries)
                {
                    switch (entry.State)
                    {
                        case EntityState.Added:
                            Console.WriteLine("Adding a {0}", entry.Entity.GetType());
                            PrintPropertyValues(entry.CurrentValues, entry.CurrentValues.PropertyNames);
                            break;
                        case EntityState.Deleted:
                            Console.WriteLine("Deleting a {0}", entry.Entity.GetType());
                            PrintPropertyValues(entry.OriginalValues, GetKeyPropertyNames(entry.Entity));
                            break;
                        case EntityState.Modified:
                            Console.WriteLine("Modifying a {0}", entry.Entity.GetType());
                            var modifiedPropertyNames = from n in entry.CurrentValues.PropertyNames
                                                        where entry.Property(n).IsModified
                                                        select n;
                            PrintPropertyValues(entry.CurrentValues, GetKeyPropertyNames(entry.Entity).Concat(modifiedPropertyNames));
                            break;
                    }
                }
            }
            return base.SaveChanges();  //返回普通的上下文SaveChanges方法
        }

运行结果为:

所有添加/修改/删除都记录下来了,这个可以方便我们做更细微的控制,毕竟EF对实体操作的依据就是实体的各种状态。

本文源码

EF DbContext 系列文章导航:
  1. EF如何操作内存中的数据和加载外键数据:延迟加载、贪婪加载、显示加载  本章源码
  2. EF里单个实体的增查改删以及主从表关联数据的各种增删改查  本章源码
  3. 使用EF自带的EntityState枚举和自定义枚举实现单个和多个实体的增删改查  本章源码
  4. EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态  本章源码
  5. 待续....
    网友 2015/4/28 9:48:50 发表

    0 sin ip ->sin i

发表评论
用户名: 匿名