1

我正在使用 MVC4 和 EF5 代码优先。我有一个问题,即在引用具有外键的行创建新数据记录时,外键行的字段设置为空。

这是一个简化的场景:

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

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

视图模型:

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" />
}

假设我在数据中有两种颜色:1. 红色 2. 蓝色

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

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

谢谢

4

4 回答 4

1

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

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

于 2012-10-07T21:26:38.543 回答
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" />
}
于 2012-10-09T20:57:31.467 回答
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, ifPerson是您视图上的模型而不是PersonViewModel. (出于这样的原因,如果我不必使用视图模型,我更喜欢使用实体模型本身而不是视图模型。)

于 2015-03-18T03:01:55.893 回答
0

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

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

最简单的选项是您执行 db.Color.Find(model.Person.Color.Id) 并将其分配给 model.Person.Color。

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

于 2012-10-07T21:01:37.973 回答