【问题标题】:EF ObjectStateEntry OriginalValues contains CurrentValuesEF ObjectStateEntry OriginalValues 包含 CurrentValues
【发布时间】:2015-04-05 08:08:52
【问题描述】:

我正在尝试覆盖实体框架的SaveChanges() 方法来保存审计信息。我从以下内容开始:

public override int SaveChanges()
{
    ChangeTracker.DetectChanges();
    ObjectContext ctx = ((IObjectContextAdapter)this).ObjectContext;
    List<ObjectStateEntry> objectStateEntryList = ctx.ObjectStateManager.GetObjectStateEntries(
                                                         EntityState.Added
                                                       | EntityState.Modified
                                                       | EntityState.Deleted).ToList();

    foreach (ObjectStateEntry entry in objectStateEntryList)
    {
        if (!entry.IsRelationship)
        {
            //Code that checks and records which entity (table) is being worked with
            ...

            foreach (string propertyName in entry.GetModifiedProperties())
            {
                DbDataRecord original = entry.OriginalValues;
                string oldValue = original.GetValue(original.GetOrdinal(propertyName)).ToString();

                CurrentValueRecord current = entry.CurrentValues;
                string newValue = current.GetValue(current.GetOrdinal(propertyName)).ToString();

                if (oldValue != newValue)
                {
                    AuditEntityField field = new AuditEntityField
                    {
                        FieldName = propertyName,
                        OldValue = oldValue,
                        NewValue = newValue,
                        Timestamp = auditEntity.Timestamp
                    };
                    auditEntity.AuditEntityField.Add(field);
                }
            }
        }
    }
}

我遇到的问题是我在entry.OriginalValuesentry.CurrentValues 中获得的值始终是新的更新值:

【问题讨论】:

    标签: c# entity-framework audit objectstatemanager


    【解决方案1】:

    问题已经找到了:

    public ActionResult Edit(Branch branch)
    {
        if (ModelState.IsValid)
        {
            db.Entry(branch).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(branch);
    }
    

    以上述方式保存更新似乎会导致ChangeTracker 无法获取旧值。我通过简单地使用 ViewModel 进行所有必需的更新来解决此问题:

    public ActionResult Edit(BranchViewModel model)
    {
        if (ModelState.IsValid)
        {
            Branch branch = db.Branch.Find(model.BranchId);
    
            if (branch.BranchName != model.BranchName)
            {
                branch.BranchName = model.BranchName;
                db.SaveChanges();
            }
            return RedirectToAction("Index");
        }
        return View(model);
    }
    

    【讨论】:

    • 有同样的问题,但这不是bug吗?无法想象我们必须先检查每个属性,然后再决定是否保存..?! ://
    • 在第一种方法中,EF 对实体的原始值一无所知。如果原始值与当前值相同,这似乎是合乎逻辑的。检查stackoverflow.com/questions/9588352/…
    【解决方案2】:

    要从数据库中获取旧值的副本而不更新您可以使用的 EF 实体

    context.Entry(yourEntity).GetDatabaseValues().ToObject()
    

    yourEntity.GetDatabaseValues().ToObject()
    

    注意:这确实会引发数据库调用。

    【讨论】:

      【解决方案3】:

      对我来说最简单的方法是:

      var cadastralAreaDb = await _context.CadastralAreas.FindAsync(id).ConfigureAwait(false);
      
        var audit = new Audit
        {
           CreatedBy = "Edi"
         };
      
      _context.Entry(cadastralAreaDb).CurrentValues.SetValues(cadastralArea);
      await _context.SaveChangesAsync(audit).ConfigureAwait(false);
      

      这是在 ASP NET Core 3.1 中测试的

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-20
        • 1970-01-01
        • 1970-01-01
        • 2020-10-03
        • 2021-07-12
        • 1970-01-01
        相关资源
        最近更新 更多