MVC4,EF:创建具有 "hierarchical" 一对多关系的新对象
MVC4, EF : Create new object with "hierarchical" one-to-many relationship
我在创建对象时遇到问题。我的实体具有 "hierarchical" 一对多关系。一个部门可以属于另一个部门。
这是我的实体:
//Properties
[Key]
[Column(Order = 0)]
public int DivisionId { get; set; }
[Required]
[MaxLength(30)]
[Column("DivisionName", Order = 2)]
public string Name { get; set; }
//Navigation properties
public virtual Division ParentDivision { get; set; }
这是我创建新部门的方法:
public ActionResult Create()
{
ViewBag.ParentDivision = new SelectList(db.Divisions, "DivisionId", "Name");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Division division)
{
if (ModelState.IsValid)
{
db.Divisions.Add(division);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ParentDivision = new SelectList(db.Divisions, "DivisionId", "Name", division.ParentDivision.DivisionId);
return View(division);
}
在这种情况下,当我尝试创建属于另一个部门的部门时,出现 "Object reference not set to an instance of an object." 错误。
我也试过像这样更改 ViewBag:
ViewBag.ParentDivision = new SelectList(db.Divisions, "ParentDivision.DivisionId", "Name", division.ParentDivision.DivisionId);
这里创建了对象,但是没有父级划分...
我真的很困惑......如果有人有任何想法......提前谢谢你。
这与它是一种自引用关系这一事实无关。如果尚未设置 ParentDivision
,它将为 null,而 null 没有 DivisionId
属性,因此您的例外。
您需要在引用 属性 之前进行空值检查。在这种情况下,最简单的方法可能是使用三元:
division.ParentDivision != null ? division.ParentDivision.DivisionId : null
但是,无论如何,您不需要设置 selected 值。 Razer 会自动处理此问题。您也不需要创建实际的 SelectList
。 Html.DropDownListFor
需要的只是一个 IEnumerable<SelectListItem>
。如果你传递它,助手将负责创建 SelectList
并设置适当的 selected 值(如果适用)。
ViewBag.ParentDivision = db.Divisions.Select(m => new SelectListItem { Value = m.DivisionId, Text = m.Name });
然后:
@Html.DropDownListFor(m => m.ParentDivisionId, (IEnumerable<SelectListItem>)ViewBag.ParentDivision)
这又引出了另一件事。您目前没有要实际绑定的 属性。您不能直接使用 ParentDivision
,因为 select 列表只会 post 返回 id,而不是完整的 ParentDivision
实例。您需要一个 属性 来将 posted id 绑定到,无论如何,这是包含在您的实体中的一个好习惯:
[ForeignKey("ParentDivision")]
public int ParentDivisionId { get; set; }
public virtual Division ParentDivision { get; set; }
我在创建对象时遇到问题。我的实体具有 "hierarchical" 一对多关系。一个部门可以属于另一个部门。 这是我的实体:
//Properties
[Key]
[Column(Order = 0)]
public int DivisionId { get; set; }
[Required]
[MaxLength(30)]
[Column("DivisionName", Order = 2)]
public string Name { get; set; }
//Navigation properties
public virtual Division ParentDivision { get; set; }
这是我创建新部门的方法:
public ActionResult Create()
{
ViewBag.ParentDivision = new SelectList(db.Divisions, "DivisionId", "Name");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Division division)
{
if (ModelState.IsValid)
{
db.Divisions.Add(division);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ParentDivision = new SelectList(db.Divisions, "DivisionId", "Name", division.ParentDivision.DivisionId);
return View(division);
}
在这种情况下,当我尝试创建属于另一个部门的部门时,出现 "Object reference not set to an instance of an object." 错误。
我也试过像这样更改 ViewBag:
ViewBag.ParentDivision = new SelectList(db.Divisions, "ParentDivision.DivisionId", "Name", division.ParentDivision.DivisionId);
这里创建了对象,但是没有父级划分...
我真的很困惑......如果有人有任何想法......提前谢谢你。
这与它是一种自引用关系这一事实无关。如果尚未设置 ParentDivision
,它将为 null,而 null 没有 DivisionId
属性,因此您的例外。
您需要在引用 属性 之前进行空值检查。在这种情况下,最简单的方法可能是使用三元:
division.ParentDivision != null ? division.ParentDivision.DivisionId : null
但是,无论如何,您不需要设置 selected 值。 Razer 会自动处理此问题。您也不需要创建实际的 SelectList
。 Html.DropDownListFor
需要的只是一个 IEnumerable<SelectListItem>
。如果你传递它,助手将负责创建 SelectList
并设置适当的 selected 值(如果适用)。
ViewBag.ParentDivision = db.Divisions.Select(m => new SelectListItem { Value = m.DivisionId, Text = m.Name });
然后:
@Html.DropDownListFor(m => m.ParentDivisionId, (IEnumerable<SelectListItem>)ViewBag.ParentDivision)
这又引出了另一件事。您目前没有要实际绑定的 属性。您不能直接使用 ParentDivision
,因为 select 列表只会 post 返回 id,而不是完整的 ParentDivision
实例。您需要一个 属性 来将 posted id 绑定到,无论如何,这是包含在您的实体中的一个好习惯:
[ForeignKey("ParentDivision")]
public int ParentDivisionId { get; set; }
public virtual Division ParentDivision { get; set; }