2012-08-25 41 views
0

我使用EF创建了一个模型,然后在MVC中创建了一个控制器和视图。 模型类型A有一个类型为B的导航属性。所以当我创建A时,我想选择一个B验证MVC(4)和EF(4)中的导航属性

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

+0

使用Visual Studio的断点,看看你在哪里得到这个错误 – Shyju

+0

我不能:( 的建立讯息动作试验ModelState.IsValid所以它之前,我可以设置断点。 – BrendanS

回答

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.Bmodel.BId

+0

值必须是一个字符串( 。它被投入HTML毕竟)如果我使用option.ToString(),然后我得到的错误:System.Data.Entity.DynamicProxies.Company_0666B8A654DC2C6F1C8E3E01AD765AF62C7D70E1D339E44C8F4F12131B24DBB9 (公司是我的方案中的B) “这可能是更好的。虽然,绑定到FK属性,而不是您的导航项目,然后使用Id。“您可以指向此资源或解释它?谢谢 – BrendanS

+0

更新我的文章映射到FK而不是 –

+0

嗯。我想我必须把FK ID放到我自己的A部分定义中。所以我想这会验证FK只是一个标量属性。这将解决我的问题。我只是希望能有一些糖来验证下拉值返回到实际ID以确保FK的完整性。 感谢您的帮助。 – BrendanS

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); 
} 
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属性,我们需要读取数据库情境B的一次。

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