实体状态始终更改为已修改

时间:2015-04-08 23:01:38

标签: c# entity-framework

我几年来一直在使用Entity Framework。我的项目是Database First。我最近从EF 4升级到EF 6.我有代码生成模板,使用以下代码创建部分类,用于标量属性:

    Private Nullable<double> _ScalarProp;
    public virtual Nullable<double> ScalarProp
    { 
        get
        {
            return _ScalarProp;
        } 
        set
        {
            if(_ScalarProp != value)
            {
                if(IsNotifyEnabled)
                {
                    OnPropertyChanging("ScalarProp");
                    OnScalarPropChanging();
                }
                _ScalarProp = value;
                if(IsNotifyEnabled)
                {
                    OnPropertyChanged("ScalarProp");
                    OnScalarPropChanged();
                }
            }
        }
    }
    partial void OnScalarPropChanging();
    partial void OnScalarPropChanged();

我的问题是,当为一个与当前值相同的属性赋值时,上面的代码会绕过赋值语句,而实体的状态是从Unchanged变为Modified。怎么了? Change Tracker是否完全独立于模板化实体运行?如何解决此问题,以便当指定的值与当前值相同时,实体保持不变?

3 个答案:

答案 0 :(得分:1)

是否将值设置为计算结果?如果这些值是计算结果,则与双精度的等式比较可能会出现意外行为。您可能希望实现与容差的比较

if (Math.Abs(_ScalarProp.Value - value.Value) > 0.000001)
{  // etc.

(在使用之前,您需要手动检查可空类型的空值。)

答案 1 :(得分:1)

似乎问题是ChangeTracker并不试图区分新值是否与我的属性设置器的覆盖中的现有值不同。相反,它只是在调用setter时将属性标记为已修改。这对我来说似乎很奇怪,因为我认为它会尝试通过清除非更改来最小化返回数据库的流量。我很想知道这是否是其他人正在看到的行为,或者它是否是我对EF的特定实现的简单怪癖(翻译:我搞砸了一些东西)。作为一种解决方法,我将以下方法添加到我的实体的基类中:

public abstract class EntityBase: INotifyPropertyChanged, INotifyPropertyChanging
{
  ...

  public bool WasUpdated()
  {
    var entry = MyEntities.Context.Entry(this);
    if (entry.State != EntityState.Modified)
      return false;
    bool changed = false;
    foreach (var propName in entry.CurrentValues.PropertyNames)
    {
      changed = changed || (entry.CurrentValues[propName] != entry.OriginalValues[propName]  && !entry.CurrentValues[propName].Equals(entry.OriginalValues[propName]));
      if (changed)
        break;
    }
    return changed;
  }
}

我会使用这个,直到有人能够帮我弄清楚这是ChangeTracker的预期行为还是我搞砸了我的实施。

答案 2 :(得分:0)

没有答案。但我有一个工具,可以找到何时以及为什么。 添加到您的上下文类。您可以随时从即时窗口调用它。

myContext.FullDump();

public void FullDump(bool ignoreUnchanged = false)
    {

        Debug.WriteLine("=====Begin of Context Dump=======");
        var dbsetList = this.ChangeTracker.Entries();
        foreach (var dbEntityEntry in dbsetList)
        {
            if (ignoreUnchanged && dbEntityEntry.State == EntityState.Unchanged)
            {
                continue;
            }
            Debug.WriteLine(dbEntityEntry.Entity.GetType().Name + " => " + dbEntityEntry.State);
            switch (dbEntityEntry.State)
            {
                case System.Data.Entity.EntityState.Detached:
                case System.Data.Entity.EntityState.Unchanged:
                case System.Data.Entity.EntityState.Added:
                case System.Data.Entity.EntityState.Modified:
                    WriteCurrentValues(dbEntityEntry);
                    break;
                case System.Data.Entity.EntityState.Deleted:
                    WriteOriginalValues(dbEntityEntry);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
            Debug.WriteLine("==========End of Entity======");
        }
        Debug.WriteLine("==========End of Context======");
    }

    private static void WriteCurrentValues(DbEntityEntry dbEntityEntry)
    {
        foreach (var cv in dbEntityEntry.CurrentValues.PropertyNames)
        {
            Debug.WriteLine(cv + "=" + dbEntityEntry.CurrentValues[cv]);
        }
    }
    private static void WriteOriginalValues(DbEntityEntry dbEntityEntry)
    {
        foreach (var cv in dbEntityEntry.OriginalValues.PropertyNames)
        {
            Debug.WriteLine(cv + "=" + dbEntityEntry.OriginalValues[cv]);
        }
    }
}