播种代码优先 api 数据库 EF 代码优先问题

seeding code first fluent api database EF code-first issues

我在播种和创建符合我需要的数据库时遇到了问题。 我有 2 个实体;用户和部门。 一个用户需要一个部门,一个部门可以有很多用户,但同时,一个部门需要一个用户作为它的部门主管。 我可以弄清楚如何设置它,每次尝试都会导致各种异常。


这是我的上下文

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

还有我的entities(AbstractEntity只提供Id给entity-类):

  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; }

}

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

然后您需要稍微放松您的模型,以便其中一个必需的属性变为可选属性,然后您将能够正确地为您的数据库设置种子。

假设您在用户实体中将部门设置为可选。

目前您让 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 的构造函数中初始化用户 属性,这样您就不会在尝试将用户添加到部门时遇到 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);
            }
        }
    }
}

我在这里所做的是将播种任务分解成更小的部分,所以我首先创建主要用户(没有部门),然后我使用之前创建的用户创建部门,最后创建每个部门的用户.

这种方法的优点是您可以完全控制自己创建的用户、部门和负责人的数量。

希望对您有所帮助!