C# 如何绑定外键?如何在控制器类中创建具有外键的模型对象?
我有以下表格关系:C# 如何绑定外键?如何在控制器类中创建具有外键的模型对象?,c#,asp.net,asp.net-mvc,C#,Asp.net,Asp.net Mvc,我有以下表格关系: ProfileMeta 1 ----- 0...1 ProfileDetail 在我点击Profile/Create页面上的submit之后,我遇到了一个运行时错误 Cannot insert the value NULL into column 'ID', table 'ContosoUniversity1.dbo.ProfileMeta'; column does not allow nulls. INSERT fails. 我在Models/ProfileDetai
ProfileMeta 1 ----- 0...1 ProfileDetail
在我点击Profile/Create
页面上的submit之后,我遇到了一个运行时错误
Cannot insert the value NULL into column 'ID', table 'ContosoUniversity1.dbo.ProfileMeta'; column does not allow nulls. INSERT fails.
我在Models/ProfileDetail.cs中正确地引用了ProfileMeta作为外键:
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("<Navigation Property Name>")
[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; }
}
}
视图/Profile/Create.cshtml:
@model ContosoUniversity.Models.Register
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Profile</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.ProfileMeta_.Username, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileMeta_.Username, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileMeta_.Username, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileMeta_.password, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileMeta_.password, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileMeta_.password, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.Age, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.Age, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.Age, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.Location, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.Location, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.Location, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.Gender, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.Gender, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.Gender, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.HighSchool, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.HighSchool, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.HighSchool, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.UndergraduateSchool, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.UndergraduateSchool, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.UndergraduateSchool, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.GraduateSchool, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.GraduateSchool, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.GraduateSchool, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
为什么我不能添加一行ProfileMeta和一行相应的ProfileDetail?我认为数据库正在自动生成主键(或ID)
是否有必要在控制器中显式设置给定模型对象的导航属性?
另外,我是否需要在我创建的ProfileDetail对象中显式设置外键:“ProfileMetaID”?首先,我建议使用EF代码约定,而不是显式定义EF中的关系(您的声明是正确的,这只是我个人的偏好,我认为更简洁) 因此,与此相反:
//ForeignKey("<Navigation Property Name>")
[Key, ForeignKey("ProfileMeta")]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
public int ProfileMetaID {get; set;}
public virtual ProfileMeta ProfileMeta { get; set; }
EF
将在数据库中自动为您创建FK
至于您的问题,我强烈建议您使用ViewModel并包含所有您想要使用的属性。但是,如果要使用现有模型,可以使用ProfileMeta
作为基础模型,并使用model.ProfileDetail.Age
绑定ProfileDetail
的值
下面是一个例子:
您的型号(短版)
您的控制器:
(无需显式设置属性值,因为关系和EF
将处理它。)
在您的视图中(只是一个快照)
@LabelFor(model=>model.Username,htmlAttributes:new{@class=“controllabel col-md-2”})
@EditorFor(model=>model.Username,new{htmlAttributes=new{@class=“form control”})
@Html.ValidationMessageFor(model=>model.Username,“,new{@class=“text danger”})
@LabelFor(model=>model.password,htmlAttributes:new{@class=“controllabel col-md-2”})
@EditorFor(model=>model.password,new{htmlAttributes=new{@class=“form control”})
@Html.ValidationMessageFor(model=>model.password,“,new{@class=“text danger”})
@LabelFor(model=>model.profileDetail.Age,htmlAttributes:new{@class=“controllabel col-md-2”})
@EditorFor(model=>model.profileDetail.Age,new{htmlAttributes=new{@class=“form control”})
@Html.ValidationMessageFor(model=>model.profileDetail.Age,“,new{@class=“text danger”})
最后,用小提琴来说明整个概念:
在小提琴中,您将看到,如果您提供年龄,它将提交回来并显示在页面中。您是否收到错误,或者什么都没有发生?“/”应用程序中的服务器错误”当我运行MVC项目并在Profile/Create上提交表单时,实际错误是什么?您必须打开调试,才能查看完整消息。stacktrace+exception Message只需注释此行,profileDetail.ProfileMetaID=register.profileDetail\uuUid;,它可能会工作。堆栈跟踪出错:
@model ContosoUniversity.Models.Register
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Profile</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.ProfileMeta_.Username, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileMeta_.Username, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileMeta_.Username, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileMeta_.password, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileMeta_.password, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileMeta_.password, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.Age, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.Age, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.Age, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.Location, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.Location, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.Location, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.Gender, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.Gender, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.Gender, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.HighSchool, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.HighSchool, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.HighSchool, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.UndergraduateSchool, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.UndergraduateSchool, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.UndergraduateSchool, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ProfileDetail_.GraduateSchool, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.ProfileDetail_.GraduateSchool, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ProfileDetail_.GraduateSchool, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
[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);
}
//ForeignKey("<Navigation Property Name>")
[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; }
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;}
}
[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();
}
}
<div class="form-group">
@Html.LabelFor(model => model.Username, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Username, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Username, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.password, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.password, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.password, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.profileDetail.Age, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.profileDetail.Age, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.profileDetail.Age, "", new { @class = "text-danger" })
</div>
</div>