我正在使用Visual Studio MVC 5身份用户模板,并尝试通过创建包含公司信息的子表来扩展用户信息。
关于如何使用很好的示例创建这个父/子表有很多内容,所以这不是问题。我的问题是如何使用外键关系以智能和简单的方式添加/删除/更改子表?
对不起,我现在没有任何代码要显示,但是我使用了MVC 5模板,并在applicationUser模型中添加了virtual ICollection<Company>
公司,效果很好。我只是想不出如何将自定义数据添加到子表....
编辑-------------
ApplicationUser模型:(这里我使用的是userData表而不是我在文中提到的Company表)
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser
{
//Create new custom tables
//User information
public virtual ICollection<Table_UserData> UserDatas { get; set; }
public virtual Table_UserData UserData { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
//userIdentity.AddClaim(new Claim("myCustomClaim", "value of claim"));
return userIdentity;
}
}
我的表:(这里我使用的是userData表,而不是我在文中提到的Company表)
public class Table_UserData
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Controller(这里我使用的是userData表而不是我在文中提到的Company表):
public async Task<PartialViewResult> Register(RegisterUserViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.UserName, Email = model.Email};
var result = await UserManager.CreateAsync(user, model.Password);
var userName = await UserManager.FindByNameAsync(model.UserName);
ApplicationUser userModel = UserManager.FindById(userName.Id);
userModel.UserDatas.Add(new Table_UserData { FirstName = model.FirstName, LastName = model.LastName });
await UserManager.UpdateAsync(userModel);
if (result.Succeeded)
{
ModelState.Clear();
return PartialView(model);
}
AddErrors(result);
}
//Something failed, redisplay form
return PartialView(model);
}
答案 0 :(得分:0)
使用ViewModel 以下是未经测试的,只是在我的头顶,但类似的东西应该工作。
视图模型:
public class ViewModel
{
public Parent Parent { get; set; }
public Child Child { get; set; }
}
控制器:
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(
[Bind(Prefix = "Parent", Include = "ID,Field1,Field2")]Parent parent,
[Bind(Prefix = "Child", Include = "ID,ParentID,Field1,Field2")]Child child,
)
{
if(ModelState.IsValid)
{
db.Parents.Add(parent);
db.Childen.Add(child);
db.SaveChanges();
}
}
查看:
@using ViewModel
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div>
@* Parent Properties *@
@Html.LabelFor(model => model.Parent.Field1)
@Html.EditorFor(model => model.Parent.Field1)
@Html.LabelFor(model => model.Parent.Field2)
@Html.EditorFor(model => model.Parent.Field2)
@* Child Properties *@
@Html.HiddenFor(model => model.Child.ParentID)
@Html.LabelFor(model => model.Child.Field1)
@Html.EditorFor(model => model.Child.Field1)
@Html.LabelFor(model => model.Child.Field2)
@Html.EditorFor(model => model.Child.Field2)
</div>
<div>
<input type="submit" value="Create" />
</div>
}
答案 1 :(得分:0)
好的,这个答案来晚了,但它可能会帮助正在学习MVC + EF的其他人解决此问题。我的代码已经过测试,只是证明Luke提供的解决方案可以正常工作的书面记录。 对于此示例,我使用的是MS Sql Server 2012,Visual Studio 2013专业版,MVC 5。
首先,这些是我的示例表:
CREATE TABLE person(
personId int IDENTITY(1,1) NOT NULL,
personName varchar(15) NOT NULL,
personLastName varchar(15) NOT NULL,
personPhone varchar(10) NULL,
CONSTRAINT PK_person
PRIMARY KEY CLUSTERED (personId ASC)
);
CREATE TABLE pet(
petId int IDENTITY(1,1) NOT NULL,
personId int NOT NULL,
petName varchar(20) NOT NULL,
petType varchar(20) NOT NULL,
CONSTRAINT PK_pet PRIMARY KEY CLUSTERED ([petId] ASC, [personId] ASC),
CONSTRAINT FK_pet_person
FOREIGN KEY(personId)
REFERENCES person (personId)
);
它是使用自动生成的键列(身份)的一对多关系。 pet 表具有一个引用 person 表主键的外键。 为了将数据添加到子表(在此示例中为pet表),我将使用ViewModel类,该类将在View中充当模型。
以下是模型:
namespace WebApp.Models
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
// The [Table()] attribute is used to map this class to a database table.
// The table name must be written exactly as it is in the database.
[Table("person")]
public partial class person
{
// This attribute was added manually. The scaffolded class did not include it.
// It MUST be indicated that the key column is identity.
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int personId { get; set; }
[Required(ErrorMessage = "First name is required.")]
[StringLength(15)]
[Display(Name="First name")]
public string personName { get; set; }
[Required(ErrorMessage = "Last name is required.")]
[StringLength(15)]
[Display(Name="Last name")]
public string personLastName { get; set; }
[StringLength(10)]
[Display(Name="Phone number")]
public string personPhone { get; set; }
public virtual ICollection<pet> pets { get; set; }
}
}
namespace WebApp.Models
{
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("pet")]
public partial class pet
{
[Key, Column(Order = 0)]
// Same thing here: DatabaseGeneratedOption was originally "none"
// It was manually changed to "Identity"
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int petId { get; set; }
// This is the foreign key column
[Key, Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int personId { get; set; }
[Required(ErrorMessage = "Pet name is required.")]
[StringLength(20)]
[Display(Name="Pet name")]
public string petName { get; set; }
[Required(ErrorMessage = "Pet type is required.")]
[StringLength(20)]
[Display(Name="Pet type")]
public string petType { get; set; }
public virtual person person { get; set; }
}
}
这是ViewModel:
using WebApp.Models;
namespace WebApp.ViewModels
{
public class personPetVM
{
public person persons { get; set; }
public pet pets { get; set; }
}
}
它只是一个包含两个属性的类,其中每个属性类型都是我们在模型中定义的类。 为了使这些类与数据库通信,我们具有以下上下文:
namespace WebApp.Models
{
using System.Data.Entity;
public partial class petContext : DbContext
{
// DBConn is defined in the Web.Config file
public petContext()
: base("name=DBConn") {
}
public virtual DbSet<person> people { get; set; }
public virtual DbSet<pet> pets { get; set; }
}
}
这是控制器:
using System.Web.Mvc;
using WebApp.Models;
using WebApp.ViewModels;
namespace WebApp.Controllers
{
public class personController : Controller
{
// Create an instance of the context class to get connected to the Database
petContext db = new petContext();
public ActionResult Index() {
// Create an instance of the ViewModel class
// and pass it to the View as its model.
personPetVM person = new personPetVM();
return View(person);
}
[HttpPost]
[ValidateAntiForgeryToken]
// Because the ViewModel contains the definition of two different classes
// it is imperative to differentiate the properties belonging to each class
// by using the [Bind(Prefix="")] attribute in the action method parameters.
// As you can see, the parameters are instances of the model classes and are
// automatically populated with the values posted on the form.
public ActionResult saveData([Bind(Prefix = "persons")] person Person,
[Bind(Prefix = "pets")] pet Pet) {
try {
// ModelState is a dictionary that contains the state of the model
// and its validation rules.
if (ModelState.IsValid) {
db.people.Add(Person);
db.pets.Add(Pet);
db.SaveChanges();
}
return RedirectToAction("Index");
}
catch {
return View();
}
}
}
}
由于我们的ViewModel类未定义键列,因此Visual Studio无法为您自动生成视图,因此您必须手动编写它:
@model WebApp.ViewModels.personPetVM
@{
ViewBag.Title = "Index";
}
<h2>Pets registry</h2>
@using (Html.BeginForm("saveData", "person", FormMethod.Post)) {
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Person</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.persons.personName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.persons.personName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.persons.personName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.persons.personLastName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.persons.personLastName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.persons.personLastName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.persons.personPhone, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.persons.personPhone, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.persons.personPhone, "", new { @class = "text-danger" })
</div>
</div>
<h4>Pet</h4>
<hr />
<div class="form-group">
@Html.LabelFor(model => model.pets.petName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.pets.petName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.pets.petName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.pets.petType, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.pets.petType, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.pets.petType, "", 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>
}
请注意,前缀会添加到所有表单生成的输入(id和name)中。在此特定示例中,所有输入的ID均由模型名称+下划线+输入名称组成。例如:“ persons_personName”。 输入名称将生成为型号名称+点+输入名称。例如:“ persons.personName”
前缀是Razor Views向参与表单的数据库表分配值的方式。
如果要使用javascript / jQuery引用任何输入id /名称,请考虑这一点,尤其是如果您自己将数据库表字段添加到表单(选择,输入等)中时。如果打算将其值发布到控制器,请确保按照指示添加相应的前缀。否则,该表单将不会更新数据库,因为某些输入值未通过模型中指定的验证规则。
就这样! 我希望这个例子可以帮助想知道如何做的人: