c# - 无法在 Entity Framework 5 中检索 OriginalValues

标签 c# asp.net-mvc-4 entity-framework-5

我正在编写一个 asp.net mvc4 应用程序,我正在使用 Entity Framework 5。我的每个实体都有像 EnteredByEnteredOnLastModifiedBy< 这样的字段LastModifiedOn

我正在尝试使用 SavingChanges 事件自动保存它们。下面的代码是从众多博客、SO answeres 等中整理出来的。

public partial class myEntities : DbContext
{
    public myEntities()
    {            
        var ctx = ((IObjectContextAdapter)this).ObjectContext;
        ctx.SavingChanges += new EventHandler(context_SavingChanges);
    }

    private  void context_SavingChanges(object sender, EventArgs e)
    {

        ChangeTracker.DetectChanges();

        foreach (ObjectStateEntry entry in
                 ((ObjectContext)sender).ObjectStateManager
                   .GetObjectStateEntries
                    (EntityState.Added | EntityState.Modified))
        {         
            if (!entry.IsRelationship)
            {
                CurrentValueRecord entryValues = entry.CurrentValues;               

                if (entryValues.GetOrdinal("LastModifiedBy") > 0)
                {
                    HttpContext currContext = HttpContext.Current;
                    string userName = "";
                    DateTime now = DateTime.Now;

                    if (currContext.User.Identity.IsAuthenticated)
                    {
                        if (currContext.Session["userId"] != null)
                        {
                            userName = (string)currContext.Session["userName"];
                        }
                        else
                        {
                            userName = currContext.User.Identity.Name;
                        }
                    }

                    entryValues.SetString(
                      entryValues.GetOrdinal("LastModifiedBy"), userName);
                    entryValues.SetDateTime(
                      entryValues.GetOrdinal("LastModifiedOn"), now);

                    if (entry.State == EntityState.Added)
                    {
                        entryValues.SetString(
                          entryValues.GetOrdinal("EnteredBy"), userName);
                        entryValues.SetDateTime(
                          entryValues.GetOrdinal("EnteredOn"), now);
                    }
                    else
                    {                
                     string enteredBy = 
                  entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy"));
                     DateTime enteredOn =
entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn"));

                        entryValues.SetString(
                       entryValues.GetOrdinal("EnteredBy"),enteredBy);
                        entryValues.SetDateTime(
                        entryValues.GetOrdinal("EnteredOn"), enteredOn);

                    }
                }
            }
        }
    }
}

我的问题是 entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy"))entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn")) 不返回原始值,而是返回 null 的当前值。我测试了实体中的其他字段,它们返回了在 html 表单中输入的当前值。

如何获取这里的原始值?

最佳答案

我认为问题可能在于您正在使用模型绑定(bind)器提供的实例作为 Controller 方法的输入,因此 EF 对该实体及其原始状态一无所知。您的代码可能如下所示:

public Review Update(Review review)
{
    _db.Entry(review).State = EntityState.Modified;
    _db.SaveChanges();
    return review;
}

在这种情况下,EF 对正在保存的 Review 实例一无所知。它信任您并将其设置为已修改,因此它会将其所有属性保存到数据库中,但它不知道该实体的原始状态\值。

检查 this tutorial实体状态和附加和保存更改方法部分.您还可以查看 this article 的第一部分,这表明 EF 如何不知道原始值并将更新数据库中的所有属性。

由于 EF 需要了解原始属性,您可以先从数据库加载您的实体,然后使用在 Controller 中接收到的值更新其属性。像这样:

public Review Update(Review review)
{
    var reviewToSave = _db.Reviews.SingleOrDefault(r => r.Id == review.Id);
    //Copy properties from entity received in controller to entity retrieved from the database
    reviewToSave.Property1 = review.Property1;
    reviewToSave.Property2 = review.Property2;
    ...

    _db.SaveChanges();
    return review;
}

这样做的好处是,只有修改后的属性才会在数据库中发送和更新,并且您的 View 和 View 模型不需要公开业务对象中的每个字段,只需公开那些可以由用户更新的字段。 (为 viewModels 和 models\business 对象打开了不同类的大门)。明显的缺点是您将对数据库造成额外的命中。

我在上面引用的教程中提到的另一个选项是让您以某种方式保存原始值(隐藏字段、 session 等),并在保存时使用原始值将实体作为未修改的附加到数据库上下文。然后使用编辑的字段更新该实体。但是,除非您真的需要避免额外的数据库命中,否则我不推荐这种方法。

希望对您有所帮助!

关于c# - 无法在 Entity Framework 5 中检索 OriginalValues,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18557243/

相关文章:

c# - 多个资源文件与单个资源文件

javascript - 禁用 Div 标签时无法获取值

asp.net-mvc - 为什么在更新父级时,Entity Framework会插入子级?

c# - 无法使用现有数据库运行 EF5 迁移

c# - EF 选择小于等于 5 的最大值

c# - 我的代码已被 Norton 检测到病毒(Sonar)

C# 抽象类实现

c# - Entity Framework 5.0 查询结果不同于对数据库的直接 SQL 查询

c# - SharedAssemblyInfo.cs

c# - 创建 ObservableCollection<T> 类