根据检测到的变化,ChangeTracker为实体分配不同的状态,如Added、Modified、Deleted和Unchanged,从而决定在调用SaveChanges方法时如何与数据库进行交互。 SaveChanges流程:当调用SaveChanges方法时,ChangeTracker会遍历所有被跟踪的实体,根据其状态生成相应的SQL命令。 关键注释:修改blog.MainPost.Title后,相关实体状态变为Modified;再次SaveChanges后,状态变为Unchanged。 (); } } } } 功能说明:在附加实体后,手动将实体状态设置为Modified,确保SaveChanges方法能正确更新数据库。 关键注释:entry.State = EntityState.Modified将实体状态设置为Modified,使SaveChanges可以执行更新操作。
在调用SaveChanges时,通过比较当前实体状态与原始快照,确定哪些属性发生了变化,从而生成准确的SQL语句。 在SaveChanges过程中,ChangeTracker遍历所有实体,根据其状态生成相应的数据库操作命令。 Entity state after Remove: {context.Entry(newBlog).State}"); // 保存更改 context.SaveChanges 最后调用SaveChanges持久化变更。 "http://blog3.com" } }; context.Blogs.AddRange(blogs); context.SaveChanges
在调用SaveChanges方法时,ChangeTracker会遍历所有跟踪的实体,根据其状态执行相应的数据库操作,如插入(Added状态)、更新(Modified状态)或删除(Deleted状态)。 ChangeTracker自动检测 context.ChangeTracker.AutoDetectChangesEnabled = true; context.SaveChanges var user = new User { Name = "John" }; context.Users.Add(user); context.SaveChanges // 错误:未调用context.Entry(retrievedUser).State = EntityState.Modified; context.SaveChanges 例如,在批量插入1000个实体的测试中,启用状态自动检测时,SaveChanges方法的执行时间可能是禁用时的数倍。
instance session.Delete("ToDoTasks/1-A"); // delete by ID 这里咬住,Delete 方法并不会删除文档,只是将文档在会话中标记为在已删除,只有在调用 SaveChanges 我们修改或者删除文档后,同样也需要调用SaveChanges 方法来更新 RavenDB,而且利用 Query 查询出来的文档在会话中也只有一个实例,不管你查询了多少次。 person = new Person { Name = "Oscar Arava" }; session.Store(person); 同样,与 Delete 方法一样,只有在调用 SaveChanges SaveChanges() SaveChanges 方法的作用是检查所有删除和更改的会话状态,然后将这些作为一个事务发送到服务器,因此这就保证了不会因为中途产生异常而部分保存失败。 调用 SaveChanges 方法时,将检查数据库中加载的实体和当前的实体是否有变动。如果有变动,那么该实体将被保存到数据库中。
ModelState.IsValid) //后台的验证信息 { db.CarModel.AddObject(car); db.SaveChanges db.CarModel.Attach(model); UpdateModel(model); db.SaveChanges = new Model.HotelModelContainer(); db.Customer.Add(entity); int count = db.SaveChanges null) { db.Customer.Remove(cus); } int count = db.SaveChanges true; db.Entry(entity).State = EntityState.Modified; int count = db.SaveChanges
Gender = "male" }; db.User.Add(user); db.SaveChanges //方法二:把当前实体的状态改为删除 //db.Entry(user).State = EntityState.Deleted; db.SaveChanges //把当前实体的状态改为Modified db.Entry(user).State = EntityState.Modified; db.SaveChanges setEntry.SetModifiedProperty("Name"); setEntry.SetModifiedProperty("Age"); db.SaveChanges Gender = "male" }; db.User.Add(user1); db.SaveChanges
SaveChanges的外移 在之前介绍EF Core的时候,我们提到过使用EF需要在每次使用之后,调用一次SaveChanges将数据提交给数据库。 在实际开发中,我们不能添加一条数据或者做一次修改就调用一次SaveChanges,这完全不现实。 因为每次调用SaveChanges是EF向数据库提交变更的时候,所以EF推荐的是每次执行完用户的请求之后统一提交数据给数据库。 这样就会造成一个问题,可能也不是问题:我们需要一个接口来管理EF 的SaveChanges操作。 我的建议是创建一个ActionFilter,针对所有的控制器进行SaveChanges进行处理。
"张三", Age = 12 } db.User.Attach(user); db.Entry(user).State = EntityState.Unchanged; db.SaveChanges 标记为 Added 状态时,表明尸体上下文被追踪但是不存在于数据库中,当我们调用 SaveChanges 方法时数据将保存进数据库。 = new User() { Name = "张三" Age = 12 } db.Entry(user).State = EntityState.Added; db.SaveChanges (); } 三、Deleted 如果需要将实体从数据库中删除,可以使用 Deleted 状态,当调用 SaveChanges 方法时数据将会从数据库中删除。 (); } 四、Modified 当我们修改数据时,需要用到 Modified 状态,当调用 SaveChanges 方法时数据将会修改数据库中的数据。
使用SaveChangesInterceptor需要实现DbContextInterceptor类中的BeforeSaveChanges和AfterSaveChanges方法,分别在执行SaveChanges BlogContext>() .UseSqlServer(connectionString) .AddInterceptors(new TimestampInterceptor()); 这样,当SaveChanges context.Database.EnsureCreated(); context.TestEntities.IgnoreQueryFilters().ExecuteDelete(); context.SaveChanges test data context.TestEntities.Add(new SoftDeleteEntity() { Id = 1, Name = "test" }); context.SaveChanges 1); ArgumentNullException.ThrowIfNull(testEntity); context.TestEntities.Remove(testEntity); context.SaveChanges
下面要说一下 上下文的 context.SaveChanges()了。 我们应该都知道的,如果我们操作上下文对数据库进行了 增、删、改的操作,那么操作结束后需要有一个 context.SaveChanges()的操作,用来把对实体的修改保存到数据库中。 这里呀,我们明明可以只交互一次就搞定的呀,怎么做呢,我们可以在把SaveChanges()的操作从UserDal中迁移到UserService中的呀,在UserDal中的每个方法先不写context.SaveChanges () 13 { 14 return DbContextFactory.GetCurrentDbContext().SaveChanges(); 15 当然,不要忘记回到Dal层,把原来代码中的SaveChanges操作去掉:去掉后代码如下: 1 public class BaseDal<T> where T : class , new() 2
ef.Users.FirstOrDefault(p => p.Id == userId); user1.Name = "李四"; db.SaveChanges (); user2.Name = "王五"; ef.SaveChanges(); } } ef.Users.FirstOrDefault(p => p.Id == userId); user1.Name = "李四"; db.SaveChanges 函数来处理异常并正确解决冲突,最后在调用 SaveChanges 方法重试提交数据。 捕获并发异常,其实我们也可以自定义 SaveChanges 的扩展方法来处理并发异常。
.)); } 自动重试与事物 对于执行自动重试策略来说,每一次调用context.SaveChanges()方法将会当做一个重试单元。 如果你的事物中有多个SaveChanges操作,配置的自动重试策略将会抛出异常,解决方法是使用委托来手动调用执行策略。 context.Blogs.Add(new Blog {Url = "http://blogs.msdn.com/dotnet"}); context.SaveChanges (); context1.SaveChanges(); transaction.Complete(); } strategy.ExecuteInTransaction(db, operation: context => { context.SaveChanges
public override int SaveChanges(SaveOptions options) { foreach (EntityObject entity System.Reflection.BindingFlags.Instance).SetValue(entity, null); } } return base.SaveChanges
每一条数据,都单独调用一次SaveChanges。 5000条数据,就意味着5000次网络往返,5000次事务开启和提交。数据库相当于被按在地上反复摩擦,不卡才怪。 二、第一版优化:批量AddRange + 单次SaveChanges 最基础、最不用动脑子的优化,就是把循环里的SaveChanges移到外面,先把所有数据存到集合里,最后一次性提交。 因为SaveChanges没执行之前,订单的自增Id还是0,明细要关联主表Id,根本关联不上。 这不是我瞎想的,实际业务里,主表和明细的关联是刚需,这个方案看似简单,其实根本没法用。 三、第二版优化:利用Identity自动返回Id 其实EF Core有个很实用的特性,很多人可能不知道:执行SaveChanges后,自增Id会自动填充到实体对象上。 绝对不要在循环里调用SaveChanges,除非你明确知道数据量极少(比如不到10条),否则就是在给数据库“下毒”; 2.
= context; } return context; } } public int SaveChanges throw dbEx; } catch (Exception ex) { Logger.Info("SaveChanges ex; } } while (saveFailed); return i; } } 这里我们主要定义一个属性Database和一个方法SaveChanges SaveChanges就是调用Database的SaveChanges方法来保存数据的修改,当然,我们对该方法进行了一些封装,让他更饱满一些。 repo = new Kiba_UserRepo(); repo.Add(new Kiba_User() { UserName = "kiba518" }); repo.SaveChanges
当调用SaveChanges时,所有的更改将通过事务一次性提交到数据库。 同时,我们注意到Insert、Update、Delete方法都显式的调用了SaveChanges方法。 至此,我们完成了从实体到聚合再到仓储的定义和实现,万事俱备,只欠Uow。 4.5. 但这似乎引入了另外一个问题,因为仓储是管理单一聚合的,每次做增删改时都显式的提交了更改(调用了SaveChanges),在处理多个聚合时,就无法利用DbContext进行批量提交了。那该如何是好? 我们抽离SaveChanges方法,定义IUnitOfWork接口。 中Insert、Update、Delete方法中的显式保存调用_dbContext.SaveChanges();。
UserInfo user = new UserInfo(); user.userName = "BBB"; user.passWord = "23456"; db.UserInfo.Add(user); db.SaveChanges (); 需要注意的是,在执行完添加操作之后,需要执行 db.SaveChanges() 操作, 这句话的意思是,把我们修改的内容更新到数据库中。 user.passWord = "1234567"; 然后执行修改操作: db.Entry(user).State = EntityState.Modified; 最后将修改保存到数据库中 db.SaveChanges user.userId = 3; user.userName = "DDD"; db.Entry(user ).Property(u => u.userName).IsModified = true; db.SaveChanges UserInfo(); user.userId = 3; db.Entry<UserInfo>(user).State = System.Data.Entity.EntityState.Deleted; db.SaveChanges
m) { try { Model.Add(m); Entities.SaveChanges { try { Model.AddRange(m); Entities.SaveChanges ) { try { Model.Remove(t); Entities.SaveChanges try { Model.RemoveRange(m); return Entities.SaveChanges model = Entities.Set<TM>(); model.RemoveRange(tmMs); return Entities.SaveChanges
"飞龙"; student.Phone = "110"; schoolDB.Student.AddObject(student); schoolDB.SaveChanges Unchanged 自对象附加到上下文中后,或自上次调用 SaveChanges 方法后,此对象尚未经过修改。 Added 对象为新对象,并且已添加到对象上下文,但尚未调用 SaveChanges 方法。 在保存更改后,对象状态将更改为 Unchanged。 Modified 对象上的一个标量属性已更改,但尚未调用 SaveChanges 方法。 ObjectContext 的 SaveChanges 方法根据每个对象的 EntityState 处理附加到上下文的实体和更新数据源。
EF Core通过ChangeTracker跟踪需要写入数据库的更改,当需要保存数据时,调用DbContext的SaveChanges方法完成保存。 // remove var lastBlog = context.Blogs.Last(); context.Blogs.Remove(lastBlog); context.SaveChanges (); } 关联数据 在EF Core中,除了独立的模型外,还有与模型关联的数据,这部分数据通过独立模型添加到模型中,在SaveChanges时将会持久化到数据库中。 默认情况下,每次SaveChanges方法的所保存的所有更改都将在一个事务中,要么全部保存成功,要么全部保存失败。此种情况已能满足大多数应用的需要。 工作原理:每当在 SaveChanges 期间执行更新或删除操作时,会将数据库上的并发令牌值与通过 EF Core 读取的原始值进行比较。如果一致则可以完成操作,如果不一致,则终止事务。