我在显示和保存导航属性时遇到了问题。使用实体框架显示和保存导航属性4 MVC3
我有3个表:
RateProfile
- RateProfileID
- 摘要名称
率
- RateID
- RateProfileID
- PanelID
- 量
面板
- PanelID
- PanelName
我有这些和外键导航属性的每个模型(即Rates
是RateProfile
的导航属性)。我有一个以RateProfile
作为模型的编辑页面。在此页面上,我有一个PanelID
的下拉菜单。下拉式过滤器显示哪些导航属性(每个panelID
有28个关联的速率)。每当下拉列表发生变化时,它会发布到我的Edit
方法(在继续之前保存现有数据并显示新选择的panelID
的费率)。
我只通过ViewBag
将需要的费率记录传递给我的列表。
我最初使用foreach循环
foreach(PDR.Models.Rate rate in ViewBag.Rates){
@Html.HiddenFor(modelItem => rate.RateProfileID)
@Html.HiddenFor(modelItem => rate.RateID)
@Html.HiddenFor(modelItem => rate.PanelID)
@Html.EditorFor(modelItem => rate.Amount)
@Html.ValidationMessageFor(modelItem => rate.Amount)
}
随着foreach循环,改变下拉时PanelID
,即它将与每个面板的正确率显示一切正常显示。但是,我的费率都不会与我的模型一起传递回我的控制器中的HTTPPost编辑方法。传递给我的控制器的RateProfile
将在其Rates栏导航属性中有0条记录(视图中有28条记录)。
我被建议将foreach循环改为for(int i ...)循环。显然,foreach循环将所有的文本框命名为同一个东西,而普通的for循环则根据索引命名它们。
使用for(int i ...)循环时,Rates导航属性在传递给HTTPPost Edit方法时的确具有它的所有记录,并且能够根据我输入的内容更新这些记录。
但是...现在使用for(int i ...)循环,页面将不会显示基于panelID
的正确记录(即使已更改,它始终显示默认panelID
的记录)。更令人疯狂的是,如果我在我的观点中提出了断点,我发现正确的Rate
记录正在传递给View仍然存在。我发现正确的RateID
/amount
等都被放入Html帮助器中,但是当页面实际显示时,它显示的是在更改下拉菜单之前存在的数据,而不是正在观看的数据,它以调试模式填充。
这里是因为从foreach循环切换到正常的循环我使用的视图代码:
@{List<PDR.Models.Rate> rates = ViewBag.rates;
var count = rates.Count;
}
@for (int i = 0; i < count; i++)
{
@Html.HiddenFor(modelItem => rates[i].RateProfileID)
@Html.HiddenFor(modelItem => rates[i].RateID)
@Html.HiddenFor(modelItem => rates[i].PanelID)
@Html.EditorFor(modelItem => rates[i].Amount)
@Html.ValidationMessageFor(modelItem => rates[i].Amount)
}
在我看来,检查调试模式下的价值观,我知道,正确率正在传递到ViewBag.rates
根据panelID
。问题是,尽管我可以在调试中逐步完成它,并且观察它为上述循环中的每个速率设置了RateID,PanelID
和Amount
的正确值,但页面上实际显示的值总是panelID == 1
的值,然后传递给我的控制器的值始终是价格的值,其中panelID == 1
而不是我传递给视图的费率。
下面是编辑方法的代码。我很确定这个问题在视图中,因为rateprofile
(它应该是我的视图中的模型)永远不会获得正确的导航属性。
[HttpPost]
public ActionResult Edit(RateProfile rateprofile, int panelID)
{
var panels = db.Panels;
ViewBag.PanelDropDown = new SelectList(panels, "PanelID", "PanelName", panelID);
ViewBag.PanelID = panelID;
if (ModelState.IsValid)
{
db.Entry(rateprofile).State = EntityState.Modified;
foreach (Rate rate in rateprofile.Rates)
{
db.Entry(rate).State = EntityState.Modified;
}
db.SaveChanges();
}
rateprofile = db.RateProfiles.Include(a => a.Rates).Where(a => a.RateProfileID == rateprofile.RateProfileID).Single(); //reloads the current rateprofile from the db
PopulatePanelDropDown(rateprofile, panelID); //populates the ViewBag.rates variable
return View(rateprofile);
}
总结:
foreach循环在
Rates
:显示一切正常基于panelID
,但不会值传递给控制器。for(int i ...)loop:只会显示
panelID == 1
的值,并且不会根据panelID
进行更新。将保存,但只有与panelID == 1
相关的记录。
你不需要'for'循环,你可以使用'foreach'。诀窍是获取输入名称属性,当通过HTTP POST发送到服务器时,可以告诉默认模型绑定器如何构建复杂的viewmodel集合(for循环有助于此,但并非完全必要)。看看这些链接:http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx http://blog.stevensanderson.com/2010/01/28/编辑一个变量长度列表aspnet-mvc-2样式https://github.com/danludwig/BeginCollectionItem – danludwig 2012-07-19 04:06:53
@danludwig:感谢您的链接。这是有道理的。 – 2012-07-28 23:22:34