如何绑定外键?如何创建与控制器类外键模型对象? [英] How to bind Foreign Key? How to create Model objects with foreign key in controller class?
问题描述
我有以下表之间的关系:
I have the following table relationships:
ProfileMeta 1 ----- 0...1 ProfileDetail
我得到一个运行时错误,当我点击提交关于资料/创建
页
Cannot insert the value NULL into column 'ID', table 'ContosoUniversity1.dbo.ProfileMeta'; column does not allow nulls. INSERT fails.
我已经正确引用ProfileMeta在型号/ ProfileDetail.cs一个ForeignKey的:
I've properly referenced ProfileMeta as a ForeignKey in Models/ProfileDetail.cs:
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; }
}
}
型号/ ProfileMeta.cs:
Models/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<MessageDetail> MessageDetails { get; set; }
public virtual ICollection<ConversationMeta> ConversationMetas { get; set; }
}
}
有关功能注册/注册页面,我创建了一个模型:注册,引用ProfileMeta和ProfileDetail
For a functional signup/register page, I have created a Model: "Register", that references ProfileMeta and 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:
Views/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")
}
ProfileController.cs:
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)的。
Why can't I add a row of ProfileMeta and a corresponding row of ProfileDetail? I thought the database is automatically generating Primary Key (or ID)'s.
是否有必要明确设置导航属性在控制器中给定的Model对象?
另外,我需要明确设置外键:ProfileMetaID,在我创造了ProfileDetail对象
Is it necessary to explicitly set the Navigation Properties for a given Model object in the controller? Also, do I need to explicitly set the Foreign Key: "ProfileMetaID" in the ProfileDetail object I had created?
推荐答案
第一件事,我想建议使用EF code约定,而不是明确地定义在EF的关系(你的声明是正确的,它只是一个个人preference对我来说,我认为这是更清洁)。
First thing, I would like to suggest to use EF code conventions instead of explicitly defining the relationships in EF (Your declaration is correct , it's just a personal preference for me and i think it's cleaner).
因此,而不是这样的:
So instead of this:
//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; }
EF
将在DB中的 FK
自动为您创建。
EF
will create the FK
automatically for you in the DB.
至于你的问题,我强烈建议您使用视图模型,包括所有你想要一起工作的属性。但如果你想使用你现有的模型,你可以使用 ProfileMeta code>为您的基本模型,并结合
ProfileDetail
的值使用 model.profileDetail.Age
As for your question , I highly recommend that you use ViewModel and include all the attributes you want work with. but if you want to use your existing models , You can use ProfileMeta
as your base model and bind the values of ProfileDetail
using model.profileDetail.Age
下面是一个例子:
您的模型(精简版)
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
将照顾它。)
Your controller:
(No need to explicitly set the values of your attributes since the relationship and EF
will take care of it.)
[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>
最后这里有一个小提琴来说明整体概念: https://dotnetfiddle.net/N0prMA
在拨弄你会看到,如果你提供了一个时代,将提交回来,并在页面中显示出来。
In the fiddle you will see that if you provide an age it will submit it back and display it in the page.
这篇关于如何绑定外键?如何创建与控制器类外键模型对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!