MVC 5身份如何添加到自定义用户子表?

时间:2015-12-02 09:22:32

标签: entity-framework asp.net-mvc-5 asp.net-identity

我正在使用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);
        }

2 个答案:

答案 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 /名称,请考虑这一点,尤其是如果您自己将数据库表字段添加到表单(选择,输入等)中时。如果打算将其值发布到控制器,请确保按照指示添加相应的前缀。否则,该表单将不会更新数据库,因为某些输入值未通过模型中指定的验证规则。

就这样! 我希望这个例子可以帮助想知道如何做的人:

  • 将模型类映射到数据库表。
  • 在模型类中定义键列。
  • 创建ViewModels。
  • 将值绑定到操作方法。
  • 将数据插入单个表中。
  • 将数据插入一对多关系。
  • 使用一些常见的实体框架[属性]
  • 验证视图中的表单。
相关问题