简体   繁体   English

种子代码优先流利的api数据库EF代码优先问题

[英]seeding code first fluent api database EF code-first issues

im having trouble seeding and creating a database matching my needs. 我在播种和创建符合我需要的数据库时遇到了麻烦。 I have 2 entities; 我有2个实体; User and Department. 用户和部门。 A User requires a department, and a department can have many users, but at the same time, a Department requires a single user to be its DepartmentChief. 用户需要一个部门,一个部门可以有多个用户,但同时,一个部门需要一个用户作为其DepartmentChief。 I can figure out how i can set this up, every attempt has resulted in exceptions of various kind. 我可以弄清楚如何进行设置,每次尝试都会导致各种异常。


Here is my context : 这是我的情况

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

And my entities (AbstractEntity only provides Id to entity-classes): 和我的实体 (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; }

}

Well, you're having all this errors because you've created circular required dependencies between your entities and now the database doesn't know how to insert them properly. 嗯,您遇到了所有这些错误,因为您已经在实体之间创建了循环所需的依赖关系,现在数据库不知道如何正确插入它们。

You'll need then to loose your model a bit so one of the required properties becomes optional and then you'll be able to seed your database correctly. 然后,您需要稍微放松一下模型,以便所需的属性之一变为可选,然后就可以正确地播种数据库了。

Let's say you set the Department as optional in your User entity. 假设您在用户实体中将“部门”设置为可选。

At the moment you are letting EF to generate your foreign key as you're not defining it on your OnModelCreating method. 目前,由于您没有在OnModelCreating方法上定义外键,因此让EF生成外键。

So start by exposing your foreign key on your user: 因此,首先将外键暴露给用户:

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

Note that I've set it as nullable so we can now define this relationship as optional: 请注意,我已将其设置为可为空,因此我们现在可以将此关系定义为可选:

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

Ensure you initialize your Users property on Department's constructor so you don't get a NullReferenceException trying to add users to the departments: 确保在Department的构造函数上初始化Users属性,以便在尝试将用户添加到Department时不会出现NullReferenceException:

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

Create a new migration and update your database. 创建一个新的迁移并更新您的数据库。 Then you can use this initializer: 然后,您可以使用以下初始化程序:

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

What I've done here is decompose the seeding task into smaller pieces, so I first create the chief users (with no department), later I create the departments with the previously created users and lastly the users for each departments. 我在这里所做的是将播种任务分解为较小的部分,因此我首先创建主要用户(不包含部门),然后创建具有先前创建的用户的部门,最后创建每个部门的用户。

The advantage of this method is that you have full control over how many users, departments and chiefs you create. 这种方法的优点是您可以完全控制创建的用户,部门和负责人的数量。

Hope this helps! 希望这可以帮助!

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

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