【发布时间】:2011-05-17 20:22:02
【问题描述】:
我目前正在以个人项目的形式第二次学习 MvcMusicStore 教程。这次我尝试使用 nHibernate 和一些使用 Castle Windsor 的 IoC,而不是实体框架。
我遇到的第一个障碍与嵌套类和模型绑定有关。我能够显示专辑列表,然后对其进行编辑。只要我编辑 Title、Price 或 AlbumArtUrl 字段,我还能够持久保存对数据库的更改。当我尝试编辑 Artist 或 Genre 字段时,会出现以下错误。
“'MvcMusicStore.Models.Album' 类型的模型无法更新。”
此错误发生在对 UpdateModel 的调用中,因此我假设它与绑定有关,但我完全不知道如何继续。从我在 StackOverflow 和其他地方进行的搜索来看,这似乎是一个常见问题,但到目前为止我还没有找到解决方案。
我希望有人能发现我在这里做错了什么并提出解决方案。
专辑
public class Album
{
public virtual int AlbumId { get; set; }
public virtual Artist Artist { get; set; }
public virtual Genre Genre { get; set; }
public virtual string Title { get; set; }
public virtual decimal Price { get; set; }
public virtual string AlbumArtUrl { get; set; }
}
StoreManagerViewModel
public class StoreManagerViewModel
{
public Album Album { get; set; }
public IList<Artist> Artists { get; set; }
public IList<Genre> Genres { get; set; }
}
编辑.aspx
<%@ Page Language="C#" MasterPageFile="/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MvcMusicStore.ViewModels.StoreManagerViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit - <%: Model.Album.Title %>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit Album</h2>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Edit Album</legend>
<%: Html.EditorFor(model => model.Album,
new { Artists = Model.Artists, Genres = Model.Genres}) %>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
专辑.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MvcMusicStore.Models.Album>" %>
<div class="editor-label">
<%: Html.LabelFor(model => model.Title) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Title) %>
<%: Html.ValidationMessageFor(model => model.Title) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Price) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Price, String.Format("{0:F}", Model.Price)) %>
<%: Html.ValidationMessageFor(model => model.Price) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.AlbumArtUrl) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.AlbumArtUrl) %>
<%: Html.ValidationMessageFor(model => model.AlbumArtUrl) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Artist)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Artist, new SelectList(ViewData["Artists"] as IEnumerable, "ArtistId", "Name", Model.Artist))%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Genre)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Genre, new SelectList(ViewData["Genres"] as IEnumerable, "GenreId", "Name", Model.Genre))%>
</div>
StoreManagerController
public ActionResult Edit(int id)
{
var viewModel = new StoreManagerViewModel
{
Album = AlbumRepository.GetById(id),
Genres = GenreRepository.GetAll().ToList(),
Artists = ArtistRepository.GetAll().ToList(),
};
return View(viewModel);
}
[HttpPost, UnitOfWork]
public ActionResult Edit(int id, FormCollection formValues)
{
var album = AlbumRepository.GetById(id);
try
{
UpdateModel(album, "Album");
AlbumRepository.SaveOrUpdate(album);
return RedirectToAction("Index");
}
catch
{
var viewModel = new StoreManagerViewModel
{
Album = album,
Genres = GenreRepository.GetAll().ToList(),
Artists = ArtistRepository.GetAll().ToList(),
};
return View(viewModel);
}
}
更新 1:
如果我在 UpdateModel 处断点并查看 ValueProvider.GetValue("Album.Artist"),我可以看到更新后的 ArtistId。这表明我完全误解了这应该如何工作。
我真的应该让 UpdateModel 处理它可以这样处理的属性吗:
UpdateModel(album, "Album", new string[] { "Title", "Price", "AlbumArtUrl" });
然后通过自己根据 ValueProvider 中的 ArtistId、GenreId 获取对象来手动更新 Artist 和 Genre 属性?
更新 2
某种修复?
专辑.ascx
<div class="editor-label">
<%: Html.LabelFor(model => model.Artist)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Artist, new SelectList(ViewData["Artists"] as IEnumerable, "ArtistId", "Name", Model.Artist.ArtistId))%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Genre)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.Genre, new SelectList(ViewData["Genres"] as IEnumerable, "GenreId", "Name", Model.Genre.GenreId))%>
</div>
StoreManagerController
UpdateModel(album, "Album", new string[] { "Title", "Price", "AlbumArtUrl" });
album.Artist = ArtistRepository.GetById(Int32.Parse(formValues["Album.Artist"]));
album.Genre = GenreRepository.GetById(Int32.Parse(formValues["Album.Genre"]));
AlbumRepository.SaveOrUpdate(album);
这行得通,我不知道这种事情应该怎么做。如果不是这样,我会很感激有人让我正确吗?
【问题讨论】:
标签: c# asp.net-mvc-2