当前位置: 首页 > news >正文

分析对手网站的优化方法淘宝商城

分析对手网站的优化方法,淘宝商城,渭南网站建设哪家好,wordpress 4.9.8创建侧边栏EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态 原文:EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态本文目录 查看实体当前、原始和数据库值#xff1a;DbEntityEntry查看实体的某个属性值#xff1a;… EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态 原文:EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态本文目录 查看实体当前、原始和数据库值DbEntityEntry查看实体的某个属性值GetValueTValue方法拷贝DbPropertyValues到实体ToObject方法修改DbPropertyValues当前值索引器克隆实体Clone方法设置实体的值SetValues方法克隆实体SetValues获取和设置实体的单个属性Property方法查询实体的属性是否被修改IsModified方法修改导航属性重新加载实体Reload方法读取相关联的实体和状态DbContext.ChangeTracker.Entries方法EF里如何解决更新时的冲突重写上下文的SaveChanges方法记录结果集里实体的各种增/删/改本文源码和系列文章导航文章开始前建议大家为了更好的记忆最好自己实现文中的所有方法。如果非要直接运行我的demo必要的时候需要恢复下数据库数据否则找不到记录。 之前的章节已经演示了context.Entry方法可以拿到实体的状态EntityState来看一个方法 /// summary/// 单个实体的状态/// /summaryprivate static void PrintState(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var canyon (from d in context.Destinationswhere d.Name Grand Canyonselect d).Single();DbEntityEntryDbContexts.Model.Destination entry context.Entry(canyon);Console.WriteLine(Before Edit{0}, entry.State); //Unchaged canyon.TravelWarnings Take a lot of Water!;DbEntityEntryDbContexts.Model.Destination entrys context.Entry(canyon);Console.WriteLine(After Edit{0}, entrys.State); //Modified}} context.Entry方法有两个重载分别返回泛型DbEntityEntryTEntity和非泛型的DbEntityEntry它们都可以监测到实体的状态并且通过DbEntityEntry还可以操作实体的当前值、原始值和数据库值。分别是 当前值Current Value程序里设置实体属性的值在内存中还没提交数据库原始值Original Value被数据库上下文跟踪到时的值程序取出数据库的值可能不是最新的数据库值Database Value数据库里的值此时此刻数据库里最新的值来看一个例子 /// summary/// 打印实体当前、原始和数据库值/// /summaryprivate static void PrintLodgingInfo(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var hotel (from d in context.Lodgingswhere d.Name Grand Hotelselect 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/4.2版本的一个bug解决办法修改实体和上下文到一个命名空间或者使用EF4.3 release。看看本书作者Julie Lerman在msdn论坛上关于此bug的回复 换成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/// 测试打印添加和删除时实体当前、原始和数据库值/// /summaryprivate static void PrintLodgingInfoAddAndDelete(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var hotel (from d in context.Lodgingswhere d.Name Grand Hotelselect d).Single();PrintChangeTrackingInfo(context, hotel); //默认var davesDump (from d in context.Lodgingswhere d.Name Daves Dumpselect 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/// 通用的打印实体方法/// /summaryprivate 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());}} 看看打印结果 之前打印实体的各种属性都是通过遍历的形式PrintPropertyValues方法打印出来如果仅取某个字段当然没必要这么麻烦可以使用GetValueTValue /// summary/// 打印实体单个属性/// /summaryprivate static void PrintOriginalName(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var hotel (from d in context.Lodgingswhere d.Name Grand Hotelselect d).Single();hotel.Name Super Grand Hotel;string originalName context.Entry(hotel).OriginalValues.GetValuestring(Name);Console.WriteLine(Current Name: {0}, hotel.Name); //Super Grand HotelConsole.WriteLine(Original Name: {0}, originalName); //Grand Hotel}} 拷贝DbPropertyValues到实体ToObject方法 /// summary/// 拷贝DbPropertyValues到实体ToObject方法/// /summaryprivate static void TestPrintDestination(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var reef (from d in context.Destinationswhere d.Name Great Barrier Reefselect 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当前值/// /summaryprivate static void ChangeCurrentValue(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var hotel (from d in context.Lodgingswhere d.Name Grand Hotelselect 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/// /summaryprivate static void CloneCurrentValues(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var hotel (from d in context.Lodgingswhere d.Name Grand Hotelselect 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方法/// /summaryprivate static void UndoEdits(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var canyon (from d in context.Destinationswhere d.Name Grand Canyonselect 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/// /summaryprivate static void CreateDavesCampsite(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var davesDump (from d in context.Lodgingswhere d.Name Daves Dumpselect d).Single();var clone new DbContexts.Model.Lodging();context.Lodgings.Add(clone);context.Entry(clone).CurrentValues.SetValues(davesDump); //克隆davesDump的值到新对象clone里clone.Name Daves Camp; //修改Name属性context.SaveChanges(); //最后提交修改 Console.WriteLine(Name: {0}, clone.Name); //Daves CampConsole.WriteLine(Miles: {0}, clone.MilesFromNearestAirport); //32.65Console.WriteLine(Contact Id: {0}, clone.PrimaryContactId); //1}} exec sp_executesql Ninsert [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(),N0 nvarchar(200),1 decimal(18,2),2 int,3 int,4 nvarchar(128),0NDaves Camp,132.65,21,31,4NLodging 很明显实体已经被克隆了。 获取和设置实体的单个属性Property方法 /// summary/// 获取和设置实体的单个属性Property方法/// /summaryprivate static void WorkingWithPropertyMethod(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var davesDump (from d in context.Lodgingswhere d.Name Daves Dumpselect d).Single();var entry context.Entry(davesDump);entry.Property(d d.Name).CurrentValue Daves Bargain Bungalows; //设置Name属性 Console.WriteLine(Current Value: {0}, entry.Property(d d.Name).CurrentValue); //Daves Bargain BungalowsConsole.WriteLine(Original Value: {0}, entry.Property(d d.Name).OriginalValue); //Daves DumpConsole.WriteLine(Modified: {0}, entry.Property(d d.Name).IsModified); //True}} 同样可以查询出实体的哪些属性被修改了IsModified方法 /// summary/// 查询实体被修改字段IsModified方法/// /summaryprivate static void FindModifiedProperties(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var canyon (from d in context.Destinationswhere d.Name Grand Canyonselect 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列 IEnumerablestring modifiedProperties from name in propertyNameswhere entry.Property(name).IsModifiedselect name;foreach (var propertyName in modifiedProperties){Console.WriteLine(propertyName); //Name、TravelWarnings}}} 前面的章节已经讲解了如何查询一对一、一对多等关系的导航属性了还不了解的点这里。现在讲讲如何修改导航属性 /// summary/// 修改导航属性ReferenceCurrentValue方法/// /summaryprivate static void WorkingWithReferenceMethod(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var davesDump (from d in context.Lodgingswhere d.Name Daves Dumpselect 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.Destinationswhere d.Name Great Barrier Reefselect d).Single();entry.Reference(d d.Destination).CurrentValue reef; //修改Console.WriteLine(Current Value After Change: {0}, davesDump.Destination.Name);}} 打印结果Current Value After Load: Grand CanyonCurrent Value After Change: Great Barrier Reef 注上面的方法并没有调用上下文的SaveChanges方法故程序跑完数据也不会保存到数据库本文所有方法仅作演示都未提交数据库。 有Reference找单个属性的那么自然也有Collection找集合属性的 /// summary/// 修改导航属性CollectionCurrentValue方法/// /summaryprivate static void WorkingWithCollectionMethod(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var res (from r in context.Reservationswhere r.Trip.Description Trip from the databaseselect 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: 1Payments After Add: 2 从数据库取出实体加载到内存中可能并不立马就展示给用户看。在进行一系列的排序、筛选等操作再展示出来。但是怎么确定展示的时候这些实体没有被修改过呢可以使用Reload方法重新加载 /// summary/// 取当前最新的数据库值Reload方法/// /summaryprivate static void ReloadLodging(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var hotel (from d in context.Lodgingswhere d.Name Grand Hotelselect 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 HotelState Before Reload: UnchangedName After Reload: Le Grand HotelState 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 NameState Before Reload: ModifiedName After Reload: Le Grand HotelState After Reload: Unchanged 注意代码里修改的Name已经显示了并且标记实体状态为Modified了Modified会在调用上下文的SaveChanges方法的时候提交到数据库。这个过程是这样的 加载实体到内存中 - 在内存中对实体的某个属性进行修改 - 使用ExecuteSqlCommand方法执行sql修改数据库里该实体的值 - 调用Reload取出数据库里本实体的最新值 - 调用SaveChanges方法的话在内存中对实体的修改也会被提交到数据库 之前操作了单个实体现在看看如何读取关联实体和状态。使用DbContext.ChangeTracker.Entries方法      /// summary/// 读取相关联的实体和状态DbContext.ChangeTracker.Entries方法/// /summaryprivate static void PrintChangeTrackerEntries(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var res (from r in context.Reservationswhere r.Trip.Description Trip from the databaseselect 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: AddedEntity Type: DbContexts.Model.Reservation - State: UnchangedEntity Type: DbContexts.Model.Payment - State: Unchanged EF里如何解决更新数据时的冲突 正常根据实体的主键修改实体的时候EF是不会判断数据修改之前有没有被别的人修改过但是如果做了并发控制EF在更新某条记录的时候才会抛错。这个系列文章的demo里有两个实体做了并发控制Person类的SocialSecurityNumber字段被标记了ConcurrencyCheckTrip类的RowVersion字段被标记了Timestamp。来写一个触发DbUpdateConcurrencyException异常的方法并处理这个异常 /// summary/// 修改实体/// /summaryprivate 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 databaseselect 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/// 尝试保存/// /summaryprivate 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/// 解决冲突/// /summaryprivate 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 Nupdate [dbo].[Trips] set [Description] 0, [CostUSD] 1 where (([Identifier] 2) and ([RowVersion] 3)) select [RowVersion] from [dbo].[Trips] where ROWCOUNT 0 and [Identifier] 2,N0 nvarchar(max) ,1 decimal(18,2),2 uniqueidentifier,3 binary(8),0NGetaway in Vermont,11000.00,2CF2E6BD3-7393-440C-941A- 9124C61CE04A,30x00000000000007D2 结果只保存了自己的修改 用户输入“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/// 合并/// /summaryprivate 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 Nupdate [dbo].[Trips] set [Description] 0, [CostUSD] 1 where (([Identifier] 2) and ([RowVersion] 3)) select [RowVersion] from [dbo].[Trips] where ROWCOUNT 0 and [Identifier] 2,N0 nvarchar(max) ,1 decimal(18,2),2 uniqueidentifier,3 binary(8),0NGetaway in Vermont,1400.00,2CF2E6BD3-7393-440C-941A-9124C61CE04A,30x00000000000007DC 看看结果 用户修改和ExecuteSqlCommand修改的都保存上了。 最后讲一个更实用的东西重写上下文的SaveChanges方法记录结果集里实体的各种增/删/改。先到BreakAwayContext类里添加一个属性标识使用数据库上下文的SaveChanges方法还是使用自定义的SaveChanges方法public bool LogChangesDuringSave { get; set; } 来看一个方法 /// summary/// 记录结果集的各种增 / 删 /改/// /summaryprivate static void TestSaveLogging(){using (var context new DbContexts.DataAccess.BreakAwayContext()){var canyon (from d in context.Destinationswhere d.Name Grand Canyonselect 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();}} 增加、修改、删除操作等都有。运行这个方法前需要在BreakAwayContext类里添加记录的帮助类方法 /// summary/// 记录帮助类方法/// /summaryprivate void PrintPropertyValues(DbPropertyValues values, IEnumerablestring 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 IEnumerablestring GetKeyPropertyNames(object entity){var objectContext ((IObjectContextAdapter)this).ObjectContext;return objectContext.ObjectStateManager.GetObjectStateEntry(entity).EntityKey.EntityKeyValues.Select(k k.Key);} 再在BreakAwayContext类里重写下上下文的SaveChanges方法 /// summary/// 重写SaveChanges方法/// /summarypublic override int SaveChanges(){if (LogChangesDuringSave) //根据表示判断用重写的SaveChanges方法还是普通的上下文SaveChanges方法{var entries from e in this.ChangeTracker.Entries()where e.State ! EntityState.Unchangedselect 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.PropertyNameswhere entry.Property(n).IsModifiedselect n;PrintPropertyValues(entry.CurrentValues, GetKeyPropertyNames(entry.Entity).Concat(modifiedPropertyNames));break;}}}return base.SaveChanges(); //返回普通的上下文SaveChanges方法} 运行结果为 所有添加/修改/删除都记录下来了这个可以方便我们在写程序的时候做更细微的控制毕竟EF对实体操作的依据就是实体的各种状态。 本文源码 EF DbContext 系列文章导航EF如何操作内存中的数据和加载外键数据延迟加载、贪婪加载、显示加载  本章源码EF里单个实体的增查改删以及主从表关联数据的各种增删改查  本章源码使用EF自带的EntityState枚举和自定义枚举实现单个和多个实体的增删改查  本章源码EF里查看/修改实体的当前值、原始值和数据库值以及重写SaveChanges方法记录实体状态  本章源码EF里如何定制实体的验证规则和实现IObjectWithState接口进行验证以及多个实体的同时验证  本章源码重写ValidateEntity虚方法实现可控的上下文验证和自定义验证  本章源码 posted on 2014-02-25 19:42 NET未来之路 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/lonelyxmas/p/3567534.html
http://www.zqtcl.cn/news/919079/

相关文章:

  • 建设英文商城网站网站开发工具选择
  • 沈阳市浑南区城乡建设局网站淄博哪里有网站建设平台
  • 做不锈钢管网站口碑好的定制网站建设提供商
  • 做网站推广销售wordpress 随机页面
  • 陈坤做直播在哪个网站如何在建设银行网站预约纪念币
  • 如何做网站么新网站一天做多少外链
  • 用家用路由器ip做网站营销策略方案
  • 学历教育网站建设网页前端是什么
  • 相同网站名网站县区分站点建设
  • 医疗器械网站建设方案南京网站制作系统
  • 小网站托管费用企查宝企业查询
  • 专门做特卖的网站是什么外国炫酷网站网址
  • 学习网站的建设wordpress批量拿shell
  • 中企动力做的网站推软件
  • 北京财优化沧州seo公司
  • 收到网站代码后怎么做啥是东莞网站优化推广
  • 重庆商城网站开发网站建设中英版
  • 免费企业网站开发给酒吧做网站
  • 想用自己电脑做服务器做个网站吗网站制作工作室哪家比较好
  • 这样建立网站vs2008做网站
  • 做网站创业故事好看大方的企业网站源码.net
  • 做家常菜哪个网站最好香蜜湖附近网站建设
  • 网站index.php被修改seo网络推广经理招聘
  • 南京做网站联系南京乐识网站建设培训福州
  • 比较冷门的视频网站做搬运网站建设 分析
  • 网站开发实习计划模板有做数学题的网站吗
  • 汕头 网站网页设计图片轮播切换
  • 免费ui网站美橙网站设计
  • 网站建设 海口哪里有网站设计公司
  • 广西建设监理协会官方网站网站建设的需求文档