所以我让这个演示项目几乎完全正常工作。
public class Project
{
public int ID { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
}
public class Task
{
public int ID { get; set; }
[Required]
public string Name { get; set; }
public int ProjectID { get; set; }
public virtual Project Project { get; set; }
}
控制器
public ActionResult Edit(int id)
{
var project = db.Projects.Where(p=>p.ID==id).Single();
return View(project);
}
[HttpPost]
public ActionResult Edit(Project project)
{
if (ModelState.IsValid)
{
var dbProject = db.Projects.Where(p => p.ID == project.ID).Single();
UpdateModel(dbProject);
db.SaveChanges();
TempData["Success"] = "Modelo Valido";
}
return RedirectToAction("Index");
}
查看//为项目强烈输入
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>Project</legend>
@Html.HiddenFor(model => model.ID)
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<h1>Tasks</h1>
@Html.EditorFor(m => m.Tasks)
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
EditorTemplate
@model MvcApplication2.Models.Task
<span>Task</span>
<br />
@Html.LabelFor(m => m.Name)
@Html.EditorFor(m => m.Name)
@Html.HiddenFor(m => m.ID)
@Html.HiddenFor(m => m.ProjectID)
@Html.ValidationMessageFor(m => m.Name)
视图显示此
问题在于,当我提交表单时,任务将填充除虚拟Project属性之外的所有内容...所以我得到的错误是
操作失败:无法更改关系,因为 一个或多个外键属性是不可为空的。当一个 改变了关系,相关的外键属性是 设置为空值。如果外键不支持空值, 必须定义新的关系,外键属性必须是 分配了另一个非空值,或者不相关的对象必须是 删除。
这是我的调试断点结果的图片
请帮助。
更新
我已将控制器操作更改为此
[HttpPost]
public ActionResult Edit(Project project)
{
if (ModelState.IsValid)
{
db.Entry(project).State = EntityState.Modified;
db.SaveChanges();
TempData["Success"] = "Modelo Valido";
return RedirectToAction("Index");
}
return View(project);
}
它仍然无法正常工作。 现在,对项目名称所做的更改将在数据库中正确更新。但完全忽略对任何任务名称所做的更改。
答案 0 :(得分:4)
我相信@Html.EditorFor(m => m.Tasks)
正在生成html(大约)
<label>Name</label>
<input type="text" name="Tasks[0].Name" id="auto-gen-id"/>
<input type="hidden" name="Tasks[0].ID" id = "auto-gen-id"/>
<input type="hidden" name="Tasks[0].ProjectID" id = "auto-gen-id"/>
<!--html for validation span-->
以上是为Collection中的第一个Task生成的近似html,将为集合中的每个任务生成类似的html。唯一的区别是索引将在所有输入的名称属性中递增,即Tasks[1].Name
,Tasks[1].ProjectID
等。此部分实际上将绑定到Collection<Task> Tasks
的{{1}}属性但您可以看到详细部分你没有任何输入,如
Project
Modelbinder需要具有适当命名约定的输入元素,以将值绑定到操作方法参数的所有属性。出于测试目的,您可以在编辑器模板中为任务
添加这两行<input type="whatever" name="Tasks[0].Project.ProjectID" .../>
<input type="whatever" name="Tasks[0].Project.Name" ..../>
在表单中为它们输入正确的值,您将使用这些值填充Task的Project属性。但可能不是你想要的,即两次输入项目信息,这可能不需要(如果你使用Linq sql肯定不需要)。当您调用ORM将实体附加到数据库实体时,它将知道当前任务属于哪个项目元素 旁注:当您遇到模型绑定问题时,请始终注意生成的html。只要您使用默认的模型绑定器,生成的html将指示哪些表单值将映射到模型的哪些属性。如果您在示例中拥有主要详细类型的场景,那就变得尤为重要。
答案 1 :(得分:1)
我找到了一种让这种方法发挥作用的方法,但我对这种方法并不完全满意。
请参阅此问题,了解如何重构当前代码以了解我当前的情况(希望暂时执行此操作)
Help improving (refactoring) my code. Automapper - EF - asp.net mvc-3