如何在两个对象之间关联时验证模型

时间:2014-09-04 15:02:16

标签: asp.net-mvc entity-framework validation

我正在使用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.NameBook.Title的两个基本修改视图是直截了当的。

现在我有了一个真实的世界&#34; -view,用户可以在其中编辑Book并向其添加现有的Authors。 该视图发布如下值:

Title = "Nice Book"
Authors[0].Id = 7
Authors[1].Id = 3

该视图只会发送Persons / Authors的ID。毕竟,用户在编辑Book时不会重命名作者。

所有模型绑定都很有效,控制器可以映射已发布的字段。

当作者/ Person没有(必需)Name设置时,绑定模型的验证失败。

有某种解决方法吗?目前,我省略了受影响属性的RequiredAttribute。我想不为我的(相当复杂的)模型图的每个方面创建一个视图模型,其中一些或另一个项目将被关联。

1 个答案:

答案 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;

    ...
}