【问题标题】:Get notified when an entity state changes当实体状态改变时得到通知
【发布时间】:2014-07-17 02:23:22
【问题描述】:

我正在构建一个使用实体框架(版本 6)来管理持久性的应用程序。它对我来说是全新的,但到目前为止我对它印象深刻。

我有一个问题,由于被不相关的答案淹没,我似乎无法在网上找到答案。基本上,我有向用户显示实体详细信息以供编辑的表单。我想做的是有一个保存更改按钮,该按钮根据实体的状态(或更准确地说是 DbEntityEntry)启用和禁用。

我可以从上下文中确定实体的状态,因此确定状态不是问题。它知道我遇到麻烦的状态何时发生变化。因此,可以从数据存储中加载实体并呈现实体,并且最初将处于未更改的状态。一旦用户开始编辑表单数据,实体就会被修改(由于数据绑定)。

我应该在哪里联系以收到有关实体更改的通知?我应该挂钩每个控件的更改事件还是绑定源更改事件或其他?

详情: 实体框架 6、WinForms、MySql 数据存储

【问题讨论】:

    标签: mysql winforms entity-framework


    【解决方案1】:

    如果你这样实现你的实体类:

    public class Person
    {
        public virtual int Id { get; set; }
        public virtual string SomeProperty { get; set; }
    }
    

    所以类需要是公共的,所有属性都需要是虚拟的、公共的(至少受保护的)以及它们的 setter 和 getter,然后当 DbContext 为您实例化此实体类时,它将实例化为派生自的类的实例你的实体类。此类实现接口 IEntityWithChangeTracker。因此,当您拥有 Person 实体类并且想要跟踪其中的更改时,您所要做的就是准备实现 IEntityChangeTracker 接口的类,如下所示:

    public class PersonTracker : IEntityChangeTracker
    {
        public void EntityComplexMemberChanged(string entityMemberName, object complexObject, string complexObjectMemberName)
        {
            throw new NotImplementedException();
        }
    
        public void EntityComplexMemberChanging(string entityMemberName, object complexObject, string complexObjectMemberName)
        {
            throw new NotImplementedException();
        }
    
        public void EntityMemberChanged(string entityMemberName)
        {
            throw new NotImplementedException();
        }
    
        public void EntityMemberChanging(string entityMemberName)
        {
            throw new NotImplementedException();
        }
    
        public System.Data.Entity.EntityState EntityState
        {
            get { throw new NotImplementedException(); }
        }
    }
    

    当然,您需要为这些方法提供实现。然后你可以使用下面的代码来测试它:

    using (MyDbContext context = new MyDbContext("Test"))
    {
        Person p = context.People.First();
        (p as IEntityWithChangeTracker).SetChangeTracker(new PersonTracker());
                //After that line EntityTracker will be called
        p.SomeProperty = "new value";
    }
    

    如果您想跟踪未从 db 获取的新创建实体,请不要使用 new 实例化它们,而是使用 Create 方法:

    Person p = context.People.Create();
    

    【讨论】:

    • 您的意思是“用 new 实例化它们”?那我不同意你的看法—— Create() 方法也调用构造函数。但是我们可以通过使用 new 或 Create() 来调用 Constructor,这就是区别。
    • 设置更改跟踪器是否会干扰上下文进行的跟踪? IE。我可以拥有自己的跟踪并允许上下文也进行自己的跟踪吗?还是设置自定义跟踪器会删除上下文的跟踪器?
    • 不幸的是,它似乎确实删除了 ef 跟踪器。它不起作用,但 ef 仍然会识别您在将它们保存到 db 之前所做的更改。我看到的跟踪实体的其他选项将仅实现您自己的机制,例如使用 INotifyPropertyChanged
    • 另一方面,您可以通过调用 context.People.Attach(p) 来恢复 ef Tracker
    • 我认为它比这更糟。查看源代码中的实现,如果您尝试更改 ChangeTracker,EntityObject.SetChangeTracker (entityframework.codeplex.com/SourceControl/latest#src/…) 会引发异常。
    【解决方案2】:

    我考虑使用 IEntityWithChangeTracker 接口来跟踪实体的更改。最后,我不喜欢它会删除上下文监视更改的能力并且添加上下文的跟踪器似乎失去了很多功能的方式。

    所以我最终了解了 EF 的 Code First 方法(之前使用的是 DB First 工作流程)。这让我在自定义实体类时更加灵活。

    所以我使用实体基类实现了INotifyPropertyChanged 接口,并在每个属性的设置器中触发了事件。值得查看上面链接中的 MS 实现,因为它使用可选的属性名称参数,因此您可以调用它而无需指定属性名称(在字符串中,哎呀)。

    您还可以用字符串覆盖属性名称,以防更新一个属性会影响另一个属性的值(例如,更新 FirstName 会更改只读属性 FullName)。详情请见here

    Public MustInherit Class EntityBase
        Implements INotifyPropertyChanged
    
        Protected Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
        End Sub
        Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _
            Implements INotifyPropertyChanged.PropertyChanged
    
    End Class
    

    【讨论】:

      猜你喜欢
      • 2013-10-20
      • 2017-06-14
      • 1970-01-01
      • 2016-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-30
      • 2023-02-22
      相关资源
      最近更新 更多