繁体   English   中英

一对一实体框架关系

[英]One-to-one Entity Framework relationship

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

这是Person表的模型代码:

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

    public virtual User User { get; set; }
}

这是User表的模型代码:

[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

预先感谢galaf。

您的数据库结构应如下所示

  1. 用户 :(PersonID int(PK,FK),名称nvarchar(20))
  2. (PersonID int(PK,身份),...)

将上述数据库结构转换为实体框架配置

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关系)将出现错误,反之亦然。

注意 :我建议建立一个(1-0..1关系),因为从逻辑上讲, User严格取决于人(弱实体),而Person可以在没有用户的情况下单独存在。 1:0..1的配置与上述配置非常相似,唯一的区别是通过使.HasOptional(p=>p.User)代替.HasRequired(p=>p.User)

现在,当您创建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代码可以按以下操作处理创建和编辑操作,只要两个视图相同,就可以减少编写代码。

[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)
       } 
}

希望这个能对您有所帮助

由于EF无法以这种方式处理循环引用(只能使用主键列进行处理),因此该配置将无法工作。
请在这里看看我的答案
实体与外键交叉引用时的代码优先迁移

我记得前一段时间这样做。 我认为您需要使Person类抽象化。 并让用户继承它。 我认为EF应该自动处理两个表的连接。

这是一个例子:

[Table("Person")]
public abstract class Person
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
}

[Table("User")]
public class User : Person
{
    public string Name { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Person> People { get; set; }
    public DbSet<User> Users { get; set; }
}

在配置中,我添加了一些User如下所示:

internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
    }

    protected override void Seed(MyContext context)
    {
        context.Users.AddOrUpdate(
            p => p.Name,
            new User {Name = "Test User #1"},
            new User {Name = "Test User #2"},
            new User {Name = "Test User #3"});
    }
}

下面是数据库中产生的内容

结果

此处提供了有关EF中模型继承的更多信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM