DbContext放弃更改而不处理
我有一个桌面客户端应用程序使用模态窗口来设置分层对象的属性。 由于这是一个客户端应用程序,并且对DbContext的访问不是线程化的,因此我在主窗体上使用长时间运行的上下文,将其传递给模态子项。
这些模式窗口使用PropertyGrid显示实体属性,也有取消button。 如果修改了任何数据并按下了取消button,则更改将反映在父窗体中(我无法处理DbContext object
)。
如果没有调用DbContext.SaveChanges()
方法,是否有办法放弃所做的任何更改?
更新:entity framework版本4.4。
如何在交易中包装呢?
using(var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted })){ // Do something context.SaveChanges(); // Do something else context.SaveChanges(); scope.Complete(); }
public void RejectChanges() { foreach (var entry in ChangeTracker.Entries()) { switch (entry.State) { case EntityState.Modified: case EntityState.Deleted: entry.State = EntityState.Modified; //Revert changes made to deleted entity. entry.State = EntityState.Unchanged; break; case EntityState.Added: entry.State = EntityState.Detached; break; } } }
在取消对单个实体属性所做更改的简单情况下,可以将当前值设置为原始值。
context.Entry(myEntity).CurrentValues.SetValues(context.Entry(myEntity).OriginalValues); //you may also need to set back to unmodified - //I'm unsure if EF will do this automatically context.Entry(myEntity).State = EntityState.UnModified;
或者重新加载(但是会导致db命中)
context.Entry(myEntity).Reload();
你colud尝试手动做这样的事情..不知道这适用于你的情况,但你可以试试看:
public void UndoAll(DbContext context) { //detect all changes (probably not required if AutoDetectChanges is set to true) context.ChangeTracker.DetectChanges(); //get all entries that are changed var entries = context.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged).ToList(); //somehow try to discard changes on every entry foreach (var dbEntityEntry in entries) { var entity = dbEntityEntry.Entity; if (entity == null) continue; if (dbEntityEntry.State == EntityState.Added) { //if entity is in Added state, remove it. (there will be problems with Set methods if entity is of proxy type, in that case you need entity base type var set = context.Set(entity.GeType()); set.Remove(entity); } else if (dbEntityEntry.State == EntityState.Modified) { //entity is modified... you can set it to Unchanged or Reload it form Db?? dbEntityEntry.Reload(); } else if (dbEntityEntry.State == EntityState.Deleted) //entity is deleted... not sure what would be the right thing to do with it... set it to Modifed or Unchanged dbEntityEntry.State = EntityState.Modified; } }
你可以应用这个:
context.Entry(TEntity).Reload();
我尝试它,并为我工作。
注意:此方法( 重新加载 )重新加载数据库中的实体时,将使用数据库中的值覆盖任何属性值。 调用此方法后,实体将处于Unchanged状态。
这是基于舒瓦洛夫的回答。 它增加了对导航属性更改的支持。
public void RejectChanges() { RejectScalarChanges(); RejectNavigationChanges(); } private void RejectScalarChanges() { foreach (var entry in ChangeTracker.Entries()) { switch (entry.State) { case EntityState.Modified: case EntityState.Deleted: entry.State = EntityState.Modified; //Revert changes made to deleted entity. entry.State = EntityState.Unchanged; break; case EntityState.Added: entry.State = EntityState.Detached; break; } } } private void RejectNavigationChanges() { var objectContext = ((IObjectContextAdapter)this).ObjectContext; var deletedRelationships = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted).Where(e => e.IsRelationship && !this.RelationshipContainsKeyEntry(e)); var addedRelationships = objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Where(e => e.IsRelationship); foreach (var relationship in addedRelationships) relationship.Delete(); foreach (var relationship in deletedRelationships) relationship.ChangeState(EntityState.Unchanged); } private bool RelationshipContainsKeyEntry(System.Data.Entity.Core.Objects.ObjectStateEntry stateEntry) { //prevent exception: "Cannot change state of a relationship if one of the ends of the relationship is a KeyEntry" //I haven't been able to find the conditions under which this happens, but it sometimes does. var objectContext = ((IObjectContextAdapter)this).ObjectContext; var keys = new[] { stateEntry.OriginalValues[0], stateEntry.OriginalValues[1] }; return keys.Any(key => objectContext.ObjectStateManager.GetObjectStateEntry(key).Entity == null); }