EntityFrameworks DbContext中跟踪更改的通知

时间:2015-09-21 07:14:24

标签: c# .net winforms entity-framework entity-framework-6

我正在使用Entity Framework构建数据输入应用程序,用户可以填写表单然后保存或取消。但是,如果存在可以保存到数据库的实际数据,我只希望启用“保存”按钮。

我知道DbContext.ChangeTracker。但是,无论何时发生变化,我都无法从上下文中获得通知。

我可以手动跟踪,但这很乏味且容易出错。

更新 该应用程序是一个WinForms应用程序

问题: 如何在DbContext“脏/有变化”时收到通知?

更新2

也许这可以澄清我的问题:

这是我不想要的:

using(var ctx = new DbContext()) {
  var foo = new FooEntity();
  ctx.Add(foo);
  RaiseContextIsDirty();  //<-- don't want to do this, this should be automatic
  //.....
  ctx.SaveChanges();
  RaiseContextIsClean();  //<-- don't want to do this, this should be automatic
}

我正在寻找的是这样的:

using(var ctx = new DbContext()) {
  ctx.ChangeTracker.OnDirtyChanged += ContextDirtyChanged;
  var foo = new FooEntity();
  ctx.Add(foo);   //<- fires OnDirtyChanged
  //.....
  ctx.SaveChanges();   //<- fires OnDirtyChanged
}

2 个答案:

答案 0 :(得分:0)

您可以将此代码用于DbContext.HasUnsavedChanges属性:

public partial class MyDBContext 
{
    public bool HasUnsavedChanges
    {
        get
        {
            try
            {
                return this.ChangeTracker.Entries().Any(e => e.State == EntityState.Added
                                                          || e.State == EntityState.Modified
                                                          || e.State == EntityState.Deleted);
            }
            catch (System.InvalidOperationException)
            {
                return false;
            }
        }
    }

在WPF中,将其设置为WPF命令CanExecute的{​​{1}}条件就足够了。

Windows窗体中的问题是,您需要找到一个经常触发的事件,并禁用或启用该按钮,但不要太频繁。我不认为EntityFramework中内置了任何可以向您提供此类事件的属性观察器。

您可以检查每个鼠标上的Save或该表单上的关键事件或类似事件,这与WPF内部工作方式类似,请参阅 - http://northhorizon.net/2012/better-commands-in-wpf/

答案 1 :(得分:0)

所以你可以对SaveChanges

进行重写
public class MyDbContext : DbContext
{
   public delegate void ChangeEventHandler(object sender, ChangeEventArgs e);
   public event ChangeEventHandler ChangeEvent;

   public override int SaveChanges()
   {
       var result = base.SaveChanges();

       var entitiesAdded = this.ChangeTracker.Entries.Where(x => x.State == EntityState.Added);
       var entitiesRemoved = this.ChangeTracker.Entries.Where(x => x.State == EntityState.Deleted);
       var entitiesModified = this.ChangeTracker.Entries.Where(x => x.State == EntityState.Modified);

       ChangeEvent(this, new ChangeEventArgs(entitiesAdded, entitiesRemoved, entitiesModified));

       return result;
   }

}

只需创建一个实现ChangeEventArgs的类。{/ p>即可创建EventArgs

然后你应该能够以正常的方式绑定到事件:

ctx.ChangeEvent += (s, e) => Console.WriteLine("Changes happened");

修改

我刚刚从MSDN中提取了大部分内容,我没有时间对其进行正确测试。但我不认为这个解决方案太过分了。

进一步的想法

DbSet<T>支持IDbSet<T>,因此您无法实现自己的IDbSet<T>,并且当您实施自己的Add功能时in。这将采用与上述相同的模式。

然后在你的MyDbContext中听取所有这些事件并将它们合并为1个事件或在它们到来时处理它们。