在实体框架中无法获取导航属性的更新关系 [英] Cannot get relationship to update for navigation properties in entity framework
问题描述
这是我实现的一些示例代码。
@ *我链接到我的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加载)当前管理器的数据库重新加载项目。然后设置属性。更改跟踪将再次检测管理员的更改并写入更新。
-
为
管理器$您的模型中的c $ c>导航属性:
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 toModified
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屋!