播种代码第一流畅的api数据库EF代码优先问题

时间:2016-11-30 20:30:35

标签: c# entity-framework ef-code-first ef-fluent-api

我无法播种并创建符合我需求的数据库。 我有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);
    }
}

我的实体(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; }

}

1 个答案:

答案 0 :(得分:0)

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

然后您需要稍微松开模型,以便其中一个必需属性成为可选项,然后您就可以正确地为数据库设定种子。

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

目前,您正在让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);
            }
        }
    }
}

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

此方法的优点是您可以完全控制您创建的用户,部门和负责人的数量。

希望这有帮助!