Entity framework 无法获取实体框架中导航属性的更新关系

Entity framework 无法获取实体框架中导航属性的更新关系,entity-framework,code-first,Entity Framework,Code First,我目前正在使用EF4.3和代码优先。创建我的对象是可行的(通过我的视图-仅使用自动生成的创建),但当我尝试编辑对象时,它不会保存任何与我的导航属性相关的更改。我一直是,但我不明白如何告诉我的背景关系已经改变 下面是我实现的一些示例代码 @* Snippet from my view where I link into my ViewModel. *@ <div class="row"> <div class="editor-label"> @Htm

我目前正在使用EF4.3和代码优先。创建我的对象是可行的(通过我的视图-仅使用自动生成的创建),但当我尝试编辑对象时,它不会保存任何与我的导航属性相关的更改。我一直是,但我不明白如何告诉我的背景关系已经改变

下面是我实现的一些示例代码

@* Snippet from my view where I link into my ViewModel. *@
<div class="row">
    <div class="editor-label">
        @Html.LabelFor(model => model.ManagerID)
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.ManagerID, ViewBag.Manager as SelectList, String.Empty)
        @Html.ValidationMessageFor(model => model.ManagerID)
    </div>
</div>
在我的项目对象中:

public class Project
{
    public int ProjectID { get; set; }
    [Required]
    public string Name { get; set; }

    // Navigation Properties
    public virtual User Manager { get; set; }
}
以下是存储库(我的上下文所在的位置)中相应的方法:


需要明确的是,这确实可以更新我的属性,但不会更新我的导航属性(在本例中是Manager)。感谢您的帮助。

我不太清楚您所说的导航属性到底是什么意思?你是说像外键关系?如果是,请尝试以下数据注释:

public class Project
{
    public int ProjectID { get; set; }

    [Required]
    public string Name { get; set; }

    [ForeignKey("YourNavigationProperty")]
    public virtual UserManager { get; set; }
}
更新EF上下文,看看会发生什么

更新
查看是否有效?

将状态设置为“已修改”仅将标量属性标记为已修改,而不是导航属性。您有几个选择:

  • 黑客(你不会喜欢的)

  • 从数据库中重新加载项目,包括(立即加载)当前管理器。然后设置属性。更改跟踪将再次检测管理器的更改并写入更新

  • 在模型中为
    管理器
    导航属性公开外键属性:

    public class Project
    {
        public int ProjectID { get; set; }
        [Required]
        public string Name { get; set; }
    
        public int ManagerID { get; set; }
        public virtual User Manager { get; set; }
    }
    
    现在,
    ManagerID
    是一个标量属性,将状态设置为
    Modified
    将包括此属性。此外,您不需要从数据库加载Manager用户,只需分配从视图中获得的ID即可:

    Project project = new Project();
    project.ProjectID = projectViewModel.ProjectID;
    project.Name = projectViewModel.Name;
    project.ManagerID = projectViewModel.ManagerID;
    repository.InsertOrUpdateProject(project);
    repository.Save();
    

    • 这里有几个选项,我将列出其中3个:

      选项1:使用GraphDiff *这需要将上下文的
      配置.AutoDetectChangesEnabled
      设置为true

      只需使用NuGet安装GraphDiff

      Install-Package RefactorThis.GraphDiff
      
      然后

      有关GraphDiff的更多详细信息,请参见

      选项2:查找和编辑 使用EF搜索实体以将其跟踪到上下文。然后编辑属性

      *这需要将上下文的
      配置.AutoDetectChangesEnabled
      设置为true

      选项3:使用标量属性 就性能而言,这是最好的方法,但它会让您的类陷入数据库问题。因为需要创建标量(基元类型)属性来映射Id

      *这样就不需要将
      配置.AutoDetectChangesEnabled
      设置为true。而且,您也不需要查询数据库来检索实体(前两个选项会这样做-是的,GraphDiff会在幕后执行!)


      所以我没有明确定义我的FK名称。我希望能够将我的管理器值设置为一个新的管理器(似乎可以工作),但在调用SaveChanges()时,更改实际上不会持久化到数据库中。我不知道该怎么做,太好了。非常感谢。我最初做了外键路由,但有一些问题。事实证明,这是可行的,但我必须使用导航属性定义[ForeignKey(“Name”)]属性,以便所有内容都能正确映射。接受你的回答。谢谢@user1240560:对于我答案中的名称,它实际上应该在没有ForeignKey属性的情况下工作(根据名称约定进行FK检测)。但是如果你的名字差别太大,不符合惯例规则,那么是的,你需要注释。@Slauma我爱你,其他方法应该适用于代码优先模型,但首先适用于数据库,唯一对我有效的方法是你的黑客攻击,我已经干扰了好几天,现在我不得不说我非常爱你来自未来的感谢真的很有帮助,我相信如果
      Configuration.AutoDetectChangesEnabled=true不起作用,然后检查其他选项
      
      //...
      else
      {
          var manager = project.Manager;
          project.Manager = null;
          context.Entry(project).State = EntityState.Modified;
          // the line before did attach the object to the context
          // with project.Manager == null
          project.Manager = manager;
          // this "fakes" a change of the relationship, EF will detect this
          // and update the relatonship
      }
      
      public class Project
      {
          public int ProjectID { get; set; }
          [Required]
          public string Name { get; set; }
      
          public int ManagerID { get; set; }
          public virtual User Manager { get; set; }
      }
      
      Project project = new Project();
      project.ProjectID = projectViewModel.ProjectID;
      project.Name = projectViewModel.Name;
      project.ManagerID = projectViewModel.ManagerID;
      repository.InsertOrUpdateProject(project);
      repository.Save();
      
      Install-Package RefactorThis.GraphDiff
      
      using (var context = new Context())
      {
          var customer = new Customer()
          {
              Id = 12503,
              Name = "Jhon Doe",
              City = new City() { Id = 8, Name = "abc" }
          };
      
          context.UpdateGraph(customer, map => map.AssociatedEntity(p => p.City));
          context.Configuration.AutoDetectChangesEnabled = true;
      
          context.SaveChanges();
      }
      
      var customer = new Customer()
      {
          Id = 12503,
          Name = "Jhon Doe",
          City = new City() { Id = 8, Name = "abc" }
      };
      
      using (var context = new Contexto())
      {
          var customerFromDatabase = context.Customers
                                            .Include(x => x.City)
                                            .FirstOrDefault(x => x.Id == customer.Id);
      
          var cityFromDataBase = context.Cities.FirstOrDefault(x => x.Id == customer.City.Id);
      
          customerFromDatabase.Name = customer.Name;
          customerFromDatabase.City = cityFromDataBase;                
      
          context.Configuration.AutoDetectChangesEnabled = true;
          context.SaveChanges();
      }
      
      var customer = new Customer()
      {
          Id = 12503,
          Name = "Jhon Doe",
          City_Id = 8,
          City = null
      };
      
      using (var contexto = new Contexto())
      {
          contexto.Entry(customer).State = EntityState.Modified;
          contexto.SaveChanges();
      }