【问题标题】:Validation for Navigation Properties in MVC (4) and EF (4)MVC (4) 和 EF (4) 中的导航属性验证
【发布时间】:2012-08-25 19:29:31
【问题描述】:

我用 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 的值?

【问题讨论】:

  • 使用 Visual Studio 断点,看看你在哪里得到这个错误
  • 我不能 :( Create Post 操作测试 ModelState.IsValid 所以它在我设置断点之前。

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


【解决方案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

【讨论】:

  • Value 必须是字符串(毕竟它会被放入 HTML 中)。如果我使用 option.ToString() ,则会收到错误消息: System.Data.Entity.DynamicProxies.Company_0666B8A654DC2C6F1C8E3E01AD765AF62C7D70E1D339E44C8F4F12131B24DBB9 (公司是我场景中的 B)。 “不过,绑定到 FK 属性而不是导航项可能会更好,然后使用 Id。”你能指出一个资源或解释它吗?谢谢
  • 嗯。我想我必须将 FK ID 放入我自己对 A 的部分定义中。所以我想这将验证 FK 只是一个标量属性。这将解决我的问题。我只是希望有一些糖可以将下拉值验证回实际 ID,以确保 FK 完整性。感谢您的帮助。
【解决方案2】:

所以我找到了一种(详细的)方法来吃蛋糕,而不必为 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);
}

【讨论】:

    【解决方案3】:

    另一种方法,无需添加额外字段(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 属性,我们需要从数据库上下文中读取 B 一次。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      相关资源
      最近更新 更多