MVC(4)和EF(4)中导航属性的验证

时间:2012-08-25 19:29:32

标签: c# asp.net-mvc entity-framework validation asp.net-mvc-4

我用EF创建了一个模型,然后在MVC中创建了一个控制器和视图。 模型类型A具有导航属性以键入B。因此,当我创建A时,我想选择B

用于创建控制器的MVC向导,仅查看为标量属性创建的字段。所以我把A上的创建操作更改为:

public ActionResult Create() //Create action for A
{
    List<B> b = db.B.ToList(); //db is my DataContext

    ViewData["B"] = companies.Select(option => new SelectListItem
                    {
                        Text = (option.Name.ToString()),
                        Value = (option.Id.ToString())
                    });
    return View();
}

并添加到我的观点中:

<div class="editor-label">
    @Html.LabelFor(model => model.B)
</div>
<div class="editor-field">
    @Html.DropDownListFor(model => model.B,  (IEnumerable<SelectListItem>)ViewData["B"], "---- Select B ----")
    @Html.ValidationMessageFor(model => model.B)
</div>

到目前为止,一切都很好,我得到了HTML

<select class="valid" id="B" name="B">
    <option value="">---- Select B ----</option>
    <option selected="selected" value="1">TestB</option>
</select>

然而,当我提交时,我收到错误:

The value '1' is invalid.

如果没有编写任何验证,则必须在某处自动生成。如何更正它以检查ViewData [“B”]集合ID的值?

3 个答案:

答案 0 :(得分:1)

问题是您的下拉列表的值为Id - 但该属性为B

您应该绑定到导航属性的FK。我不确定你的模型(如果这不能帮助你发布它)

<div class="editor-field">
    @Html.DropDownListFor(model => model.BId,  (IEnumerable<SelectListItem>)ViewData["B"], "---- Select B ----")
    @Html.ValidationMessageFor(model => model.BId)
</div>

注意我已将model.B更改为model.BId

答案 1 :(得分:0)

所以我找到了一个(冗长的)方法来获得我的蛋糕并且也可以吃它而不必为FK id添加额外的字段

我将POST创建操作更改为FormCollection格式。

[HttpPost]
public ActionResult Create(FormCollection collection) //POST create for A
{
    A a = new A();

    a.Name = collection["Name"];
    a.Description = collection["Description"];

    try
    {
        int bId = Int32.Parse(collection["B"]);
        a.B = db.B.First(option => option.Id == bId);
        ValidateModel(a);
    }
    catch
    {
        ModelState.AddModelError("B", new Exception("bId does not match an existing B"));
    }

    if (ModelState.IsValid)
    {
        db.A.Add(a);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    //Failed
    //Go back to create form
    List<B> blist = db.B.ToList();

    ViewData["B"] = blist.Select(option => new SelectListItem
    {
        Text = (option.Name.ToString()),
        Value = (option.Id.ToString())
    });

    return View(a);
}

答案 2 :(得分:0)

另一种不添加额外字段(A类上的BId)或从FormCollection中读取模型字段的方法是直接在视图中绑定model.b.Id。

<div class="editor-label">
    @Html.LabelFor(model => model.B)
</div>
<div class="editor-field">
    @Html.DropDownListFor(model => model.B.Id,  (IEnumerable<SelectListItem>)ViewData["B"], "---- Select B ----")
    @Html.ValidationMessageFor(model => model.B)
</div>

此绑定将Id绑定到A的导航属性B.要绑定Name属性,我们需要从数据库上下文中读取一次。

[HttpPost]
public ActionResult Create(A a){
   B b = db.Bs.Find(a.B.Id);
   a.B = b;
   db.As.Add(a);
   db.SaveChanges();
}