我正在使用Entity Framework 6.1代码和ASP.NET MVC5构建应用程序。
我有以下型号:
class Person {
public Int32 Id {get; set;}
[Required]
public String Name {get; set;}
public List<Book> Books {get; set;}
}
class Book {
public Int32 Id {get; set;}
[Required]
public String Title {get; set;}
public List<Person> Authors {get; set;}
}
更改Person.Name
或Book.Title
的两个基本修改视图是直截了当的。
现在我有了一个真实的世界&#34; -view,用户可以在其中编辑Book
并向其添加现有的Authors
。
该视图发布如下值:
Title = "Nice Book"
Authors[0].Id = 7
Authors[1].Id = 3
该视图只会发送Persons
/ Authors
的ID。毕竟,用户在编辑Book
时不会重命名作者。
所有模型绑定都很有效,控制器可以映射已发布的字段。
当作者/ Person
没有(必需)Name
设置时,绑定模型的验证失败。
有某种解决方法吗?目前,我省略了受影响属性的RequiredAttribute
。我想不为我的(相当复杂的)模型图的每个方面创建一个视图模型,其中一些或另一个项目将被关联。
答案 0 :(得分:0)
这就是你应该使用视图模型的原因。因为它们允许您自定义应该向视图公开的属性。但是,您也没有正确处理所选作者的发布。对于像这样的多选,你真的需要一个视图模型。
public class BookViewModel
{
public BookViewModel()
{
SelectedAuthorIds = new List<int>();
}
[Required]
public string Title { get; set; }
public List<int> SelectedAuthorIds { get; set; }
public IEnumerable<SelectListItem> AuthorChoices { get; set; }
}
注意,首先,没有Id
属性。如果您想使用相同的视图模型来编辑书籍,则可能需要添加此项,但出于创建目的,视图中不需要Id
字段,因此我们将其保留。接下来,没有Authors
属性。相反,我们有SelectedAuthorIds
这是一个整数列表,AuthorChoices
将保存用户可以选择的所有Author
。最后,有一个构造函数来初始化SelectedAuthorIds
所以它永远不会为空。空列表转换为未选择任何内容,但我们需要一个实际列表。
现在,使用此视图模型作为视图的模型:
@model Namespace.To.BookViewModel
并且,将您的作者选择字段更改为:
@Html.ListBoxFor(m => m.SelectedAuthorIds, Model.AuthorChoices)
您还需要填写AuthorChoices
,您将在此格式的GET操作中处理:
public ActionResult Create()
{
var model = new BookViewModel();
model.AuthorChoices = db.Authors.Select(m => new SelectListItem
{
Value = m.Id.ToString(),
Text = m.Name
});
return View(model);
}
最后,在用户发布表单后,您需要使用SelectedAuthorIds
从数据库中获取这些作者,并将其添加到正在创建的Book
中。就此而言,您还需要将数据从BookViewModel
映射到Book
的实例。所有这些意味着将数据从一个复制到另一个。有这类东西的库,比如AutoMapper,但这个相对简单,所以我会手动处理它:
[HttpPost]
public ActionResult Create(BookViewModel model)
{
if (ModelState.IsValid)
{
var book = new Book
{
Title = model.Title
};
book.Authors = db.Authors.Where(m => model.SelectedAuthorIds.Contains(m.Id));
db.Books.add(book);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
编辑版本将类似,但您将改为拉取现有Book
而不是创建新版本:
[HttpPost]
public ActionResult Edit(int id, BookViewModel model)
{
var book = db.Books.Find(id);
book.Title = model.Title;
...
}