在实体框架中无法获取导航属性的更新关系 [英] Cannot get relationship to update for navigation properties in entity framework

查看:67
本文介绍了在实体框架中无法获取导航属性的更新关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前使用的是EF4.3和Code First。创建我的对象的作品(通过我的观点 - 只是使用自动生成的Create),但是当我尝试编辑一个对象时,它不会保存任何更改,我们最终将绑定到我的导航属性。我已经阅读关系,但我不明白如何告诉我的上下文这个关系已经改变了。



这是我实现的一些示例代码。

  @ *我链接到我的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>

这是我的Controller实现(我的编辑的POST):

  [HttpPost] 
public ActionResult Edit(ProjectViewModel projectViewModel)
{
if(ModelState.IsValid)
{
Project project = new Project();
project.ProjectID = projectViewModel.ProjectID;
project.Name = projectViewModel.Name;
project.ProjectManager = repository.GetUser(projectViewModel.ManagerID);
repository.InsertOrUpdateProject(project);
repository.Save();
return RedirectToAction(Index);
}
ViewBag.Manager = new SelectList(repository.GetUsers(),UserID,FullName,projectViewModel.ManagerID);
return View(projectViewModel);
}

在我的Project对象内:

  public class Project 
{
public int ProjectID {get;组;
[必需]
public string Name {get;组; }

//导航属性
public virtual User Manager {get;组; }
}

这是从仓库(我的上下文所在的地方)的相应方法:

  public void InsertOrUpdateProject(Project project)
{
if(program.ProjectID == default ))
{
context.Projects.Add(project);
}
else
{
context.Entry(project).State = EntityState.Modified;
}
}

要清楚,这可以更新我的属性,但它不会更新导航属性(在这种情况下为Manager)。欣赏任何帮助。

解决方案

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




  • 一个黑客(你不会喜欢)

      // ... 
    else
    {
    var manager = project.Manager;
    project.Manager = null;
    context.Entry(project).State = EntityState.Modified;
    //之前的行将对象附加到上下文
    // with project.Manager == null
    project.Manager = manager;
    //这个假改变了关系,EF会检测到这个
    //并更新相关权
    }


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


  • 管理器导航属性:

      public class Project 
    {
    public int ProjectID {得到;组;
    [必需]
    public string Name {get;组; }

    public int ManagerID {get;组; }
    public virtual User Manager {get;组;
    }

    现在 ManagerID 是一个标量属性,将状态设置为修改将包含此属性。此外,您不需要从数据库加载Manager用户,您可以从视图中分配您获得的ID:

     项目项目=新项目(); 
    project.ProjectID = projectViewModel.ProjectID;
    project.Name = projectViewModel.Name;
    project.ManagerID = projectViewModel.ManagerID;
    repository.InsertOrUpdateProject(project);
    repository.Save();



I am currently using EF4.3 and Code First. Creation of my objects works (via my views - just using the auto-generated Create), but when I attempt to edit an object, it does not save any changes that, utlimately, tie back to my navigation properties. I have been reading on relationships, but I don't understand how to tell my context that the relationship has changed.

Here is some example code of my implementation.

@* 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>

Here is my Controller implementation (POST of my Edit):

    [HttpPost]
    public ActionResult Edit(ProjectViewModel projectViewModel)
    {
        if (ModelState.IsValid)
        {
            Project project = new Project();
            project.ProjectID = projectViewModel.ProjectID;
            project.Name = projectViewModel.Name;
            project.ProjectManager = repository.GetUser(projectViewModel.ManagerID);
            repository.InsertOrUpdateProject(project);
            repository.Save();
            return RedirectToAction("Index");
        }
        ViewBag.Manager = new SelectList(repository.GetUsers(), "UserID", "FullName", projectViewModel.ManagerID);
        return View(projectViewModel);
    }

Within my Project object:

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

    // Navigation Properties
    public virtual User Manager { get; set; }
}

Here is the corresponding method from the repository (where my context resides):

public void InsertOrUpdateProject(Project project)
    {
        if (program.ProjectID == default(int))
        {
            context.Projects.Add(project);
        }
        else
        {
            context.Entry(project).State = EntityState.Modified;
        }
    }

Just to be clear, this does work to update my properties, but it does not update my navigation properties (in this case, Manager). Appreciate any help.

解决方案

Setting the state to Modified only marks scalar properties as modified, not navigation properties. You have several options:

  • A hack (you won't like it)

    //...
    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
    }
    

  • Reload the project from the database including (eager loading) the current manager. Then set the properties. Change tracking will detect a change of the manager again and write an UPDATE.

  • Expose a foreign key property for the Manager navigation property in your model:

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

    Now ManagerID is a scalar property and setting the state to Modified will include this property. Moreover you don't need to load the Manager user from the database, you can just assign the ID you get from your view:

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

这篇关于在实体框架中无法获取导航属性的更新关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆