我目前正在使用EF4.3和Code First。创建我的对象(通过我的视图 - 只使用自动生成的创建),但是当我尝试编辑对象时,它不会保存任何与我的导航属性完全相关的更改。我一直是reading on relationships,但我不明白如何告诉我的情况,这种关系已经改变了。
以下是我实施的一些示例代码。
@* 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>
这是我的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; set; }
[Required]
public string Name { get; set; }
// Navigation Properties
public virtual User Manager { get; set; }
}
以下是来自存储库(我的上下文所在的位置)的相应方法:
public void InsertOrUpdateProject(Project project)
{
if (program.ProjectID == default(int))
{
context.Projects.Add(project);
}
else
{
context.Entry(project).State = EntityState.Modified;
}
}
为了清楚起见,这确实可以更新我的属性,但它不会更新我的导航属性(在本例中为Manager)。感谢任何帮助。
答案 0 :(得分:11)
将状态设置为Modified
仅将标量属性标记为已修改,而不是导航属性。您有几种选择:
黑客(你不会喜欢)
//...
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
}
从数据库重新加载项目,包括(急切加载)当前管理器。然后设置属性。更改跟踪将再次检测到经理的更改并写入更新。
在模型中公开Manager
导航属性的外键属性:
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();
答案 1 :(得分:4)
这里有几个选项,我将列出其中3个:
*这需要将您的上下文的Configuration.AutoDetectChangesEnabled
设置为true。
只需使用NuGet
安装GraphDiff即可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();
}
有关GraphDiff的详细信息,请查看here。
使用EF搜索您的实体,将其跟踪到上下文。然后编辑属性。
*这需要将您的上下文的Configuration.AutoDetectChangesEnabled
设置为true。
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();
}
在性能方面,这是最好的方法,但它会让您的课程陷入数据库问题。因为您需要创建一个标量(原始类型)属性来映射Id。
*这样就不需要将Configuration.AutoDetectChangesEnabled
设置为true。而且你也不需要对数据库进行查询以检索实体(因为前两个选项是 - 是的,GraphDiff在幕后做它!)。
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();
}
答案 2 :(得分:-2)
我不确定你的导航属性是什么意思?你的意思是外键关系吗?如果是,请尝试以下数据注释:
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; }
[ForeignKey("ManagerId")]
public ManagerModel UserManager { get; set; }
}
public class ManagerModel
{
[Key]
public int ManagerId { get; set; }
public String ManagerName { get; set; }
}
看看是否有效?