我正在使用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),但其名称将设置为空。
我确定这里发生了绑定问题?这应该作为框架中的标准支持还是我需要创建自己的模型绑定器?
由于
答案 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值来进行参考检查以确保没有人作弊。