MVC,实体框架,使用HTML.DropDownFor时将外键数据设置为null

时间:2012-10-07 20:42:24

标签: asp.net-mvc entity-framework-4.1 html.dropdownlistfor

我正在使用MVC4和EF5 codefirst。我有一个问题,即当引用具有外键的行创建新数据记录时,外键行的字段被设置为null。

这是一个简化的场景:

public class Person
{
  string name { get; set; }
  Color color { get; set; }
}

public class Color
{
  int id { get; set; }
  string name { get; set; }
}

viewmodel:

public class PersonViewModel
{
    public Person Person { get; set; }
    public IEnumerable<SelectListItem> Colors { get; set; }

    public PersonViewModel()
    {
        Context db = new Context();
        Colors = db.Colors.ToList().Select(t => new SelectListItem() { Text = t.Name, Value = t.Id.ToString() });
    }
}

控制器:

public ActionResult Create()
{
    return View(new PersonViewModel);
}

[HttpPost]
public ActionResult Create(PersonViewModel personViewModel)
{
    if (ModelState.IsValid)
    {   
        db.Person.Add(personViewModel.Person);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(personViewModel);
}

最后,创建视图:

@model PersonViewModel
@using (Html.BeginForm())
{   
    @Html.ValidationSummary(true)

    @Html.LabelFor(model => model.Person.Name) 
    @Html.EditorFor(model =>  model.Person.Name)

    @Html.LabelFor(model => model.Person.Color)
    @Html.DropDownListFor(model => model.Person.Color.Id, this.Model.Colors)

    <input type="submit" value="Create" title="Create ticket" />
}

说我在数据中有两种颜色: 红色的 2.蓝色

通过视图创建新人并选择蓝色作为颜色时,将正确创建人物,但颜色表中ID为2的“蓝色”将保持其ID(2),但其名称将设置为空。

我确定这里发生了绑定问题?这应该作为框架中的标准支持还是我需要创建自己的模型绑定器?

由于

4 个答案:

答案 0 :(得分:1)

当下拉列表将其值发布到控制器时,它仅发布值,而不是名称。因此,该名称将无法绑定。

您将不得不查找该值,或者创建一个包含名称和值的值,然后在回发时解析它以将两者分开(可能具有值“2:Blue”然后执行在回发上使用string.Split()。

答案 1 :(得分:1)

事实证明我没有正确遵循实体框架约定。通过显式定义外键列,实体框架可以正确识别关系并按预期工作。因此,新的数据模型(添加显式外键列)

public class Person
{
  string Name { get; set; }

  int ColorId { get; set; }     
  Color color { get; set; }
}

public class Color
{
  int ColorId { get; set; }
  string name { get; set; }
}

和更新后的视图(绑定在新的外键列上):

@model PersonViewModel
@using (Html.BeginForm())
{   
    @Html.ValidationSummary(true)

    @Html.LabelFor(model => model.Person.Name) 
    @Html.EditorFor(model =>  model.Person.Name)

    @Html.LabelFor(model => model.Person.Color)
    @Html.DropDownListFor(model => model.Person.ColorId, this.Model.Colors)

    <input type="submit" value="Create" title="Create ticket" />
}

答案 2 :(得分:1)

我知道您正在使用EF 5,但在EF 6中,您必须将这些导航属性声明为“虚拟”,并使用DataAnnotations标记外键:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

public class Person
{
    public string Name { get; set; }
    public int ColorId { get; set; }  

    [ForeignKey("ColorId")]
    public virtual Color color { get; set; }
}

public class Color
{
    int ColorId { get; set; }
    string name { get; set; }
}

如果您有多种颜色,则必须在public class Person内添加这两行:

public Person
{
    Colors = new HashSet<Color>();
}

public virtual ICollection<Color> Colors { get; set; }

如果Person是您视图中的模型而不是model.color.name,则可以使用Person通过PersonViewModel调用颜色。 (出于这样的原因,我更喜欢使用实体模型本身,而不是视图模型,如果我不必使用视图模型。)

答案 3 :(得分:0)

你应该在帖子中发现model.Person.Color被设置为一个新的Color实例,并正确设置了它的id。标准模型绑定器已经完成了它的工作,但实际上你希望它将它与数据库中的某些东西相关联。

从内存中你缺少外键属性,或者你可能使用流畅的api设置它。

最简单的选择是你做db.Color.Find(model.Person.Color.Id)并将其分配给model.Person.Color。

这还有一个额外的好处,即通过使用不存在的颜色注入post值来进行参考检查以确保没有人作弊。