如何绑定外键?如何创建与控制器类外键模型对象? [英] How to bind Foreign Key? How to create Model objects with foreign key in controller class?

查看:264
本文介绍了如何绑定外键?如何创建与控制器类外键模型对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下表之间的关系:

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 为您的基本模型,并结合 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆