c# – EF实体在更新时不保存相同实体类型的子属性

前端之家收集整理的这篇文章主要介绍了c# – EF实体在更新时不保存相同实体类型的子属性前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用ASP.NET MVC 5和Entity Framework 6.我有一个页面,允许用户输入流程信息.此信息的一个方面是从下拉启动过程中进行选择.这个类大致如下:

**

public class SupportProcess
  {
    [Key]
    public int ProcessId { get; set; }
    [DisplayName("Starting process?")]
    public virtual SupportProcess StartProcess { get; set; }
    public string Name { get; set; }
    [DisplayName("When is this run?")]
    public virtual ProcessSchedule ProcessSchedule { get; set; }
    [DisplayName("")]
    public string Description { get; set; }
    [DisplayName("Expected Result")]
    public string ExpectedResult { get; set; }
  }

**

我使用的视图模型具有SupportProcess的属性,选定的启动过程以及用于填充视图下拉列表的进程列表.

public class SupportProcessviewmodel
  {
    public SupportProcess SupportProcess { get; set; }
    public int SelectedStartProcess { get; set; }
    public List<SupportProcess> Processes { get; set; }

    public SupportProcessviewmodel()
    {
      this.SupportProcess = new SupportProcess();
    }
  }

我的编辑帖子操作如下:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(SupportProcessviewmodel vm)
    {
        if (ModelState.IsValid)
        {              

      if (vm.SelectedStartProcess > 0)
      {
        vm.SupportProcess.StartProcess = db.SupportProcesses.Find(vm.SelectedStartProcess);
      }
        db.Entry(vm.SupportProcess).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(vm);
}

问题是,虽然vm.SelectedStartProcess不是null并且具有适当的值,但它永远不会保存到数据库中.数据库将此字段显示为StartProcess_ProcessId.另外值得注意的是,一个进程可能有0或1个启动进程.

我想知道EF是否在数据库表中使这个属性成为一个外键,实际上它指向同一个表,这在某种程度上导致了这个问题.我全都听取了建议.

我还要补充一点,Create Post操作按预期工作.这必须与传达给EF的事情有关,即StartProcess属性也需要在实体上更新.但这是猜测…

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create( SupportProcessviewmodel vm)
    {
        if (ModelState.IsValid)
        {
            if(vm.SelectedStartProcess > 0) {
              vm.SupportProcess.StartProcess = db.SupportProcesses.Find(vm.SelectedStartProcess);
            }
            db.SupportProcesses.Add(vm.SupportProcess);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(vm);
    }

解决方法

没有显式原始FK属性的引用导航属性的问题是,影子FK状态由已从中检索实体的DbContext维护.在像您这样的断开连接的场景中丢失哪些信息.

当你调用

db.Entry(entity).State = EntityState.Modified;

对于断开连接的实体,EF会将实体附加到上下文,并将所有原始属性标记为已修改.参考导航属性被视为未更改,因此在调用SaveChanges时不会更新它们.

要让EF更新FK,了解原始参考属性值和新参考属性值至关重要.在您的情况下,传递的SupportProcess实体的StartProcess属性的原始值.

由于在断开连接的场景中(特别是像你这样的延迟加载属性)你不能依赖传递的对象属性值,我建议以下安全操作序列:

(1)将navigation属性设置为null以避免将值附加到上下文.
(2)将实体附加到上下文并将其标记为已修改.
(3)显式加载导航属性.这将导致额外的数据库跳闸,但将确保更新正常.
(4)设置导航属性的新值.当您调用SaveChanges时,上下文更改跟踪器将能够确定是否需要FK更新.

将它应用于您的案例:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(SupportProcessviewmodel vm)
{        
    if (ModelState.IsValid)
    {
        // (1)
        vm.SupportProcess.StartProcess = null;
        // (2)  
        db.Entry(vm.SupportProcess).State = EntityState.Modified;
        // (3)
        db.Entry(vm.SupportProcess).Reference(e => e.StartProcess).Load();
        // (4)
        vm.SupportProcess.StartProcess =
            vm.SelectedStartProcess > 0 ?
            db.SupportProcesses.Find(vm.SelectedStartProcess) :
            null;

        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(vm);
}

猜你在找的C#相关文章