c# - 一对一 Entity Framework 关系

标签 c# sql-server asp.net-mvc entity-framework

在我的数据模型(Entity Framework 6.1.3、ASP.NET MVC 5、Code First 和现有数据库)中有两个表,“Person”和“User”共享一对一的关系。 “用户”表的PK PersonID 列又是“Person”表的PK。我希望每当创建新的用户记录时,(首先)自动创建一个 Person 记录,然后将 Person 表中的 PersonID 的值插入到新的 User 记录中。

这是 Person 表的模型代码:

[Table("Person")]
public partial class Person
{
    public int PersonID { get; set; }

    public virtual User User { get; set; }
}

这是用户表的模型代码:

[Table("User")]
public partial class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int PersonID { get; set; }

    [Required]
    [StringLength(20)]
    public string Name { get; set; }

    public virtual Person Person { get; set; }
}

UserController.cs 代码包括:

    // POST: User/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "PersonID,Name")] User user)
    {
        if (ModelState.IsValid)
        {
            db.Users.Add(user);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        ViewBag.PersonID = new SelectList(db.People, "PersonID", "PersonID", user.PersonID);
        return View(user);
    }

Person 表的 SQL:

CREATE TABLE [dbo].[Person](
[PersonID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL
CONSTRAINT [PK_Person_PersonID] PRIMARY KEY CLUSTERED)

用户表的SQL:

CREATE TABLE [dbo].[User](
[PersonID] [int] NOT NULL,
[Name] [nvarchar](20) NOT NULL
CONSTRAINT [PK_User_PersonID] PRIMARY KEY CLUSTERED)

ALTER TABLE [dbo].[User]  WITH CHECK ADD  CONSTRAINT [FK_User_Person_PersonID] FOREIGN KEY([PersonID])
REFERENCES [dbo].[Person] ([PersonID])
GO

ALTER TABLE [dbo].[User] CHECK CONSTRAINT [FK_User_Person_PersonID]
GO

提前致谢,加拉夫。

最佳答案

你的数据库结构应该是这样的

  1. 用户:(PersonID int (PK, FK), Name nvarchar(20))
  2. (PersonID int (PK , identity), ...)

将上述数据库结构转化为 Entity Framework 配置

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure PersonID as PK for User 
    modelBuilder.Entity<User>()
        .HasKey(e => e.PersonID);

    // Configure PersonID as FK for User
    modelBuilder.Entity<Person>()
                .HasRequired(p => p.User) 
                .WithRequired(u => u.Person); 

}

如果您尝试在没有 User 的情况下单独保存 Person,则上述配置(1-1 关系)将出错,反之亦然。

Note: I recommend to build a (1-0..1 relationship) since logically the User is strictly depending on the person ( weak entity) while Person can exists alone without having a user. the configuration of 1:0..1 is very similar to the above configuration, the only difference is by making .HasOptional(p=>p.User) instead of .HasRequired(p=>p.User)

现在当你创建用户实体时,你的代码应该是这样的

var user = new User(){
   Name = "UserName",
   Person  = new Person(){
       FirstName="FirstName",
       LastName ="LastName",
       ...
   }
};

db.Users.Add(user);
db.SaveChanges();

以上代码将在您创建用户对象时强制创建人员对象。

更新:针对您的情况:

我建议您创建一个 DTO对象来管理两个对象(用户和人员)的 CRUD,如下所示

public class UserDTO 
{
    public int Id { get; set;}
    public string UserName { get;set;}
    public string Password { get;set;}
    public string FirstName { get; set;}
    public string LastName { get; set;}
    // ... any other required properties goes here ... //
}

您的 UserController.cs 代码可以在一个操作中处理创建和编辑,如下所示,只要两个 View 相同,这将允许您减少代码。

[HttpGet]
public ActionResult CreateOrEdit(int? id)
{
     UserDTO user = null;
     if( id!=null)
         user = db.Users.Select(t=> new UserDTO {
             UserName = t.UserName,
             FirstName = t.Person.FirstName,
             LastName = t.Person.LastName,
             Id = t.Id
             // ... //
         }).FirstOrDefault();
     else
         user = new UserDTO();
     return View(user);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateOrEdit(UserDTO model)
{
      if(model!=null && ModelState.IsValid)
      {
           if(model.Id>0) // Edit
           {
               User  user = db.Users.Include(p=>p.Person).Single(t=>t.Id == model.Id);
               user.UserName = model.UserName;
               user.Person.FirstName = model.FirstName;
               user.Person.LastName = model.LastName;
           }
           else // Add
           {
               User user = new User
               {
                   UserName = model.UserName,
                   Password = model.Password, // should be encrypted first
                   Person = new Person{
                      FirstName = model.FirstName,
                      LastName = model.LastName
                   }
               };
               db.Users.Add(user);
           }
           db.SaveChanges();
           return RedirectoToAction("TargetActionGoesHere");
      }
      return View(model);
}

你的 View CreateOrEdit.cshtml 应该是这样的,我不会为了简单而添加 html 代码和标签

@model UserDTO

@using(Html.BeginForm())
{
       @Html.AntiForgeryToken()
       @Html.ValidationSummary(true)
       @* To store the value of Id in hidden field*@
       @Html.HiddenFor(m=>m.Id) 
       @Html.EditorFor(m=>m.FirstName)
       @Html.EditorFor(m=>m.LastName)
       @Html.EditorFor(m=>m.UserName)
       @if(Model.Id ==0 ) 
       { 
           // only in the add case you need to get the password value
           @Html.EditorFor(m=>m.Password)
       } 
}

希望对你有帮助

关于c# - 一对一 Entity Framework 关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39604491/

相关文章:

c# - 取消设置枚举标志

c# - .NET:XML 文档 - CREF 标记中使用的程序集别名

sql - 如何使用 t-sql 检查逻辑项组合?

c# - 日期时间查询错误

c# - 在 mvc 中使用 RedirectToAction() 传递多个对象?

javascript - 动态更改 Kendo ui Grid 列标题文本和字段

c# - 在不读取整个文件的情况下获取图像尺寸

sql - 字符串或二进制数据将被截断。该语句已终止。 (长度相同)

asp.net-mvc - 如果不使用标准输出目录,则无法运行 MVC4 项目

c# - WPF 创建一个控件列表,可以通过鼠标滚动但仍保持功能