2016-11-30 115 views
0

即时播种和创建符合我的需求的数据库。 我有2个实体;用户和部门。 用户需要一个部门,而一个部门可以有很多用户,但同时部门需要一个用户作为其部门主管。 我可以弄清楚如何设置这个,每一次尝试都会导致各种异常。播种代码第一流利api数据库EF代码优先问题


这里是我的背景

public class FravaerContext : DbContext 
{ 
    public FravaerContext() : base("name=DefaultConnection") 
    { 
     Database.SetInitializer(new DBInitializer()); 
    } 


    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<User>().HasRequired<Department>(u => u.Department).WithMany(d => d.Users).WillCascadeOnDelete(false); 
     modelBuilder.Entity<Department>().HasRequired(d => d.DepartmentChief); 

     //modelBuilder.Entity<Absence>().HasRequired<User>(a => a.User).WithMany(u => u.Absences).WillCascadeOnDelete(false); 
     base.OnModelCreating(modelBuilder); 
    } 

    public DbSet<Absence> Absences { get; set; } 
    public DbSet<Department> Departments { get; set; } 
    public DbSet<User> Users { get; set; } 

} 

public class DBInitializer : DropCreateDatabaseAlways<FravaerContext> 
{ 
    protected override void Seed(FravaerContext context) 
    { 
     for (int i = 1; i <= 4; i++) 
     { 
      User chief = new User() {Id = i, Absences = new List<Absence>(), Email = $"chief{i}@chief.dk", FirstName = $"Chief{i}",LastName = $"Chiefsen{i}",Password = "admin",UserName = ""+i,Role = Role.DepartmentChief}; 

      Department d = new Department() {Id = i, Users = new List<User>() { chief }, DepartmentChief = chief }; 


      chief.Department = d; 

      context.Departments.Add(d); 
     } 
     base.Seed(context); 
    } 
} 

而且我实体(AbstractEntity只提供ID来实体类):

public class Department : AbstractEntity 
{ 
    public List<User> Users { get; set; } 
    public User DepartmentChief { get; set; } 

} 

public class User : AbstractEntity 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string UserName { get; set; } 
    public string Password { get; set; } 
    public string Email { get; set; } 
    public List<Absence> Absences { get; set; } 
    public Department Department { get; set; } 
    public Role Role { get; set; } 

} 
+0

你为什么不在'Seed'方法中调用'SaveChanges'? –

+0

我不需要。我现在工作,我从来没有使用保存更改:) – Bille

回答

0

那么,您遇到所有这些错误,因为你已经创建了循环需要你的实体之间的依赖关系,现在数据库不知道如何正确插入它们。

然后,您需要稍微放松您的模型,以便所需的属性之一变为可选属性,然后您将能够正确地对数据库进行种子处理。

假设您在用户实体中将Department设置为可选项。

此刻你让EF生成你的外键,因为你没有在你的OnModelCreating方法上定义它。

因此,通过您的用户暴露你的外键启动:

public class User : AbstractEntity 
{ 
    public int? DepartmentId { get; set; } 
} 

请注意,我已经将它设置为可为空,所以我们现在可以定义这种关系作为可选:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<User>() 
     .HasOptional(u => u.Department) 
     .WithMany(d => d.Users) 
     .HasForeignKey(x => x.DepartmentId) 
     .WillCascadeOnDelete(false); 
} 

确保您在Department的构造函数上初始化您的Users属性,以便您不会收到尝试将用户添加到部门的NullReferenceException:

public Department() 
{ 
    Users = new List<User>();  
} 

创建一个新的迁移并更新您的数据库。然后你可以使用这个初始化:

public class DBInitializer : DropCreateDatabaseAlways<FravaerContext> 
{ 
    protected override void Seed(FravaerContext context) 
    { 
     //create the users first 
     //save the users in a list so later we can create the departments 
     var users = new List<User>(); 

     for (var i = 1; i <= 4; i++) 
     { 
      var user = new User 
      { 
       Id = i, 
       Absences = new List<Absence>(), 
       Email = $"chief{i}@chief.dk", 
       FirstName = $"Chief{i}", 
       LastName = $"Chiefsen{i}", 
       Password = "admin", 
       UserName = "user" + i, 
       Role = Role.DepartmentChief 
      }; 
      users.Add(user); 
      context.Users.Add(user); 
     } 

     //create one department for each user (with that user as the chief) 
     var departmentId = 1; 

     //save the departments so later we can seed them with users 
     var departments = new List<Department>(); 
     foreach (var user in users) 
     { 
      var d = new Department 
      { 
       Id = departmentId++, 
       DepartmentChief = user 
      }; 

      departments.Add(d); 
      context.Departments.Add(d); 
     } 

     //seeed the departments with users 
     foreach (var department in departments) 
     { 
      //add 5 users to each department 
      for (var i = 1; i < 5; i++) 
      { 
       var user = new User 
       { 
        Absences = new List<Absence>(), 
        Email = $"user{department.Id}{i}@user.dk", 
        FirstName = $"User{department.Id}{i}", 
        LastName = $"Username{department.Id}{i}", 
        Password = "user", 
        UserName = "" + department.Id + i, 
        Role = Role.DepartmentChief 
       }; 
       department.Users.Add(user); 
      } 
     } 
    } 
} 

我在这里所做的是分解任务播种成小块,所以我首先创建首席用户(无部门),后来我创建了部门与先前创建用户,最后是每个部门的用户。

这种方法的优点是您可以完全控制您创建的用户,部门和首席。

希望这会有所帮助!