如何绑定外键? 如何在控制器类中使用外键创建Model对象?

我有以下表格关系:

ProfileMeta 1 ----- 0...1 ProfileDetail 

点击“ Profile/Create页面上的提交后,我收到了运行时错误

 Cannot insert the value NULL into column 'ID', table 'ContosoUniversity1.dbo.ProfileMeta'; column does not allow nulls. INSERT fails. 

我在Models / ProfileDetail.cs中正确引用了ProfileMeta作为ForeignKey:

 using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Web; namespace ContosoUniversity.Models { //ProfileMeta is Principal Class //ProfileDetail is Dependent Class public class ProfileDetail { //classNameID or ID is interpreted by EF as PK. public int ID { get; set; } //ForeignKey("") [Key, ForeignKey("ProfileMeta")] [DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)] public int ProfileMetaID {get; set;} public string UserName { get; set; } public string Age { get; set; } public string Location { get; set; } public string Gender { get; set; } //Optional Details public string HighSchool { get; set; } public string UndergraduateSchool { get; set; } public string GraduateSchool { get; set; } public virtual ProfileMeta ProfileMeta { get; set; } } } 

型号/ ProfileMeta.cs:

 using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Web; namespace ContosoUniversity.Models { //ProfileMeta is Principal //ProfileDetail is Dependent public class ProfileMeta { public int ID { get; set; } public string Username { get; set; } public string password { get; set; } public virtual ProfileDetail ProfileDetail {get; set;} public virtual ICollection MessageDetails { get; set; } public virtual ICollection ConversationMetas { get; set; } } } 

对于function注册/注册页面,我创建了一个模型:“Register”,它引用了ProfileMeta和ProfileDetail。

 using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace ContosoUniversity.Models { public class Register { public ProfileMeta ProfileMeta_ { get; set; } public ProfileDetail ProfileDetail_ { get; set; } } } 

查看/资料/ Create.cshtml:

 @model ContosoUniversity.Models.Register @{ ViewBag.Title = "Create"; } 

Create

@using (Html.BeginForm()) { @Html.AntiForgeryToken()

Profile


@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProfileMeta_.Username, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.ProfileMeta_.Username, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ProfileMeta_.Username, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProfileMeta_.password, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.ProfileMeta_.password, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ProfileMeta_.password, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProfileDetail_.Age, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.ProfileDetail_.Age, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ProfileDetail_.Age, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProfileDetail_.Location, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.ProfileDetail_.Location, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ProfileDetail_.Location, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProfileDetail_.Gender, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.ProfileDetail_.Gender, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ProfileDetail_.Gender, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProfileDetail_.HighSchool, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.ProfileDetail_.HighSchool, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ProfileDetail_.HighSchool, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProfileDetail_.UndergraduateSchool, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.ProfileDetail_.UndergraduateSchool, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ProfileDetail_.UndergraduateSchool, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.ProfileDetail_.GraduateSchool, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.ProfileDetail_.GraduateSchool, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ProfileDetail_.GraduateSchool, "", new { @class = "text-danger" })
}
@Html.ActionLink("Back to List", "Index")
@section Scripts { @Scripts.Render("~/bundles/jqueryval") }

ProfileController.cs:

  [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create(Register register) { if (ModelState.IsValid) { //Add 1 ProfileMeta row and 1 linked ProfileDetail row ProfileMeta profileMeta = new ProfileMeta(); profileMeta.Username = register.ProfileMeta_.Username; profileMeta.password = register.ProfileMeta_.password; ProfileDetail profileDetail = new ProfileDetail(); //profileDetail.ID = register.ProfileDetail_.ID; //How to assign FK below? profileDetail.ProfileMetaID = register.ProfileDetail_.ID; profileDetail.UserName = register.ProfileDetail_.UserName; profileDetail.Age = register.ProfileDetail_.Age; profileDetail.Location = register.ProfileDetail_.Location; profileDetail.ProfileMeta = profileMeta; //profileDetail.UserName = register.ProfileDetail_.UserName; //profileDetail.Age = register.ProfileDetail_.Age; //profileDetail.Location = register.ProfileDetail_.Location; profileMeta.ProfileDetail = profileDetail; db.ProfileMetas.Add(profileMeta); db.ProfileDetails.Add(profileDetail); db.SaveChanges(); return RedirectToAction("Index"); } return View(register); } 

为什么我不能添加一行ProfileMeta和一行ProfileDetail? 我以为数据库会自动生成主键(或ID)。

是否有必要在控制器中为给定的Model对象显式设置导航属性? 另外,我是否需要在我创建的ProfileDetail对象中显式设置外键:“ProfileMetaID”?

首先,我想建议使用EF代码约定,而不是明确定义EF中的关系(您的声明是正确的,它只是我个人的偏好,我认为它更清洁)。

所以不是这样的:

  //ForeignKey("") [Key, ForeignKey("ProfileMeta")] [DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)] public int ProfileMetaID {get; set;} public virtual ProfileMeta ProfileMeta { get; set; } 

你可以做:

  public int ProfileMetaID { get; set; } public virtual ProfileMeta profileMeta { get; set; } 

EF将在DB中自动为您创建FK

至于您的问题,我强烈建议您使用ViewModel并包含您想要使用的所有属性。 但是如果要使用现有模型,可以使用ProfileMeta作为基本模型,并使用model.profileDetail.Age绑定ProfileDetail的值。

这是一个例子:

你的型号(短版)

 public class ProfileDetail { [Key, DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] public int ID { get; set; } public string UserName { get; set; } public string Age { get; set; } public string Location { get; set; } public string Gender { get; set; } public int ProfileMetaID { get; set; } public virtual ProfileMeta profileMeta { get; set; } } public class ProfileMeta { [Key, DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] public int ID { get; set; } public string Username { get; set; } public string password { get; set; } public virtual ProfileDetail profileDetail {get; set;} } 

你的控制器:(不需要显式设置属性的值,因为关系和EF会处理它。)

 [HttpGet] public ActionResult Create() { return View(new ProfileMeta()); } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create(Register register) { if (ModelState.IsValid) { db.ProfileMetas.Add(profileMeta); db.ProfileDetails.Add(profileDetail); db.SaveChanges(); } } 

在您的视图中(只是一个快照)

  
@Html.LabelFor(model => model.Username, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.Username, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Username, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.password, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.password, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.password, "", new { @class = "text-danger" })
@Html.LabelFor(model => model.profileDetail.Age, htmlAttributes: new { @class = "control-label col-md-2" })
@Html.EditorFor(model => model.profileDetail.Age, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.profileDetail.Age, "", new { @class = "text-danger" })

最后,这是一个说明整个概念的小提琴: https : //dotnetfiddle.net/N0prMA

在小提琴中,您将看到如果您提供年龄,它将提交回来并在页面中显示。