C# 对同一域/实体模型的两个引用

C# 对同一域/实体模型的两个引用,c#,.net,sql-server,asp.net-mvc,entity-framework,C#,.net,Sql Server,Asp.net Mvc,Entity Framework,问题 我想保存在用户编辑时已更改的模型属性。这是我想做的 检索编辑的视图模型 获取域模型并映射回更新的值 在存储库上调用update方法 获取“旧”域模型并比较字段的值 将更改后的值(JSON)存储到表中 但是,我在第4步中遇到了问题。实体框架似乎不想再次访问数据库以获取具有旧值的模型。它只返回我拥有的相同实体 尝试的解决方案 我尝试过使用Find()和SingleOrDefault()方法,但它们只是返回我当前拥有的模型 示例代码 private string ArchiveChanges(T

问题

我想保存在用户编辑时已更改的模型属性。这是我想做的

  • 检索编辑的视图模型
  • 获取域模型并映射回更新的值
  • 在存储库上调用update方法
  • 获取“旧”域模型并比较字段的值
  • 将更改后的值(JSON)存储到表中
  • 但是,我在第4步中遇到了问题。实体框架似乎不想再次访问数据库以获取具有旧值的模型。它只返回我拥有的相同实体

    尝试的解决方案

    我尝试过使用
    Find()
    SingleOrDefault()
    方法,但它们只是返回我当前拥有的模型

    示例代码

    private string ArchiveChanges(T updatedEntity)
    {
        //Here is the problem!
        //oldEntity is the same as updatedEntity
        T oldEntity = DbSet.SingleOrDefault(x => x.ID == updatedEntity.ID);
    
        Dictionary<string, object> changed = new Dictionary<string, object>();
    
        foreach (var propertyInfo in typeof(T).GetProperties())
        {
            var property = typeof(T).GetProperty(propertyInfo.Name);
    
            //Get the old value and the new value from the models
            var newValue = property.GetValue(updatedEntity, null);
            var oldValue = property.GetValue(oldEntity, null);
    
            //Check to see if the values are equal
            if (!object.Equals(newValue, oldValue))
            {
                //Values have changed ... log it
                changed.Add(propertyInfo.Name, newValue);
            }
        }
    
        var ser = new System.Web.Script.Serialization.JavaScriptSerializer();
        return ser.Serialize(changed);
    }
    
    public override void Update(T entityToUpdate)
    {
        //Do something with this
        string json = ArchiveChanges(entityToUpdate);
    
        entityToUpdate.AuditInfo.Updated = DateTime.Now;
        entityToUpdate.AuditInfo.UpdatedBy = Thread.CurrentPrincipal.Identity.Name;
    
        base.Update(entityToUpdate);
    }
    
    private string ArchiveChanges(T updatedEntity)
    {
    //问题就在这里!
    //oldEntity与UpdateEntity相同
    T oldEntity=DbSet.SingleOrDefault(x=>x.ID==updatedEntity.ID);
    字典已更改=新字典();
    foreach(typeof(T).GetProperties()中的var propertyInfo)
    {
    var property=typeof(T).GetProperty(propertyInfo.Name);
    //从模型中获取旧值和新值
    var newValue=property.GetValue(updatedEntity,null);
    var oldValue=property.GetValue(oldEntity,null);
    //检查这些值是否相等
    如果(!object.Equals(newValue,oldValue))
    {
    //值已更改…请记录它
    添加(propertyInfo.Name,newValue);
    }
    }
    var ser=new System.Web.Script.Serialization.JavaScriptSerializer();
    返回序列序列化(已更改);
    }
    公共覆盖无效更新(T entityToUpdate)
    {
    //用这个做点什么
    字符串json=ArchiveChanges(entityToUpdate);
    entityToUpdate.AuditInfo.Updated=DateTime.Now;
    entityToUpdate.AuditInfo.UpdatedBy=Thread.CurrentPrincipal.Identity.Name;
    基本更新(entityToUpdate);
    }
    
    问题在于实体框架缓存在DbSet中读取的对象。因此,当您第二次请求该对象时,它不会进入数据库,因为它已经加载了该对象


    然而,好消息是实体自动跟踪原始值。有关如何获取它们的信息,请参见此问题:

    更新报告后是否有此代码?从你的步子上看,听起来就是这样。如果是的话,那么你会得到新的模型;您更新了旧模型。如果要执行此操作,需要在更新之前获取旧模型。@Tyrsius no its BEFORE。我添加了调用方法以获得更清晰的图片。您正在处理/更新的实体已附加到上下文(已跟踪)。这意味着如果您修改它,它将进入修改状态(这意味着当调用SaveChanges时,它将在DB中进行更新)。但是,当仅查询实体(SingleOrDefault调用)时,由于实体附加到上下文(内存缓存中),它将直接从上下文中检索,并且不会往返到DB。如果要从DB中检索实体,则需要将其从当前上下文中分离(然后重新附加该实体,以便对SaveChanges的调用将实际更新DB)。