无法在 Entity Framework 5 中检索 OriginalValues

unl*_*mit 1 c# asp.net-mvc-4 entity-framework-5

我写一个asp.net应用mvc4和我使用实体框架5.我的每一个实体都像场EnteredByEnteredOnLastModifiedByLastModifiedOn

我正在尝试使用该SavingChanges事件自动保存它们。下面的代码是从众多博客、SO 答案等中汇总的。

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);

                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

我如何在这里获得原始值?

Dan*_*.G. 5

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

public Review Update(Review review)
{
    _db.Entry(review).State = EntityState.Modified;
    _db.SaveChanges();
    return review;
}
Run Code Online (Sandbox Code Playgroud)

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

检查评为部分实体状态和附加的SaveChanges和方法本教程。您还可以查看本文的第一部分,部分展示了 EF 如何不知道原始值并更新数据库中的所有属性。

由于 EF 需要了解原始属性,您可能首先从数据库加载您的实体,然后使用控制器中收到的值更新其属性。像这样的东西:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

希望有帮助!