[英]UpdateModel for Nested Properties in ASP.NET MVC2
我目前正在作為個人項目第二次通過MvcMusicStore教程。 這次我嘗試使用nHibernate而不是Entity Framework,還嘗試使用Castle Windsor使用一些IoC。
Ive遇到的第一個障礙與嵌套類和模型綁定有關。 我無法顯示相冊列表,然后對其進行編輯。 只要編輯標題,價格或AlbumArtUrl字段,我還可以持久保存對數據庫的更改。 當我嘗試編輯“藝術家”或“流派”字段時,會發生以下錯誤。
“無法更新'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>
相冊
<%@ 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);
這行得通,我不知道它應該如何完成。 希望有人把我糾正對嗎?
您必須在UpdateModel()
提供邏輯
同樣,如果您具有強類型視圖,則可以將模型用作控制器參數,而不是FormCollection。 另外,最好排除已編輯相冊的ID。
ActionResult Edit([Bind(Exclude = "AlbumId")]Album album)
然后,您將進入表單中所有字段的相冊進行編輯。
關於您的代碼:
現在,我在您的代碼中看到您通過數據庫獲取當前專輯的ID
var album = AlbumRepository.GetById(id);
然后嘗試對其執行一些操作,目前尚不清楚如何綁定視圖中的信息。
為了解決這個問題,我在ViewModel中創建了一個屬性,該屬性鏈接到相關對象,然后將其綁定到該屬性:
public class User
{
[Required(ErrorMessage = "Your first name is required.")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Your last name is required.")]
public string LastName { get; set; }
[Required(ErrorMessage = "A logon name is required.")]
public string Logon { get; set; }
[Required(ErrorMessage = "A password is required.")]
public string Password { get; set; }
[Required(ErrorMessage = "A role is required.")]
public string Role { get; set; }
[Required(ErrorMessage = "An airport is required.")]
public Airport Airport { get; set; }
[DisplayName("Is Active")]
bool IsActive { get; set; }
}
<div class="form-field">
<div class="field-label"><%= Html.LabelFor(m => m.User.Airport) %>:</div>
<div class="field-input"><%= Html.DropDownListFor(m => m.UserAirportId, new SelectList(Model.Airports, "Id", "Name"))%></div>
<div class="field-result"><%= Html.ValidationMessageFor(m => m.User.Airport) %></div>
</div>
public class UserViewModel
{
public User User { get; set; }
public List<Airport> Airports { get; set; }
public List<String> Roles { get; set; }
//Hack to get around non-binding of complex objects by UpdateModel
public Guid UserAirportId
{
get
{
if (User != null && User.Airport != null)
return User.Airport.Id;
return Guid.Empty;
}
set
{
if (User == null)
return;
var airport = Airports.Where(m => m.Id == value).FirstOrDefault();
if (airport == null)
return;
User.Airport = airport;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.