如何使用 Entity Framework Code First 创建一个带有两个指向相同 table 的外键的 table

How to create a table with two foreign keys pointing to the same table using Entity Framework Code First

我有以下 classes,我试图首先使用 Entity Framework 6 代码将其存储在数据库中。

人:

public class Person
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    public List<WorkItem> WorkItems { get; set; }
}

工作项:

public class WorkItem
{
    public Guid Id { get; set; }

    public string Description { get; set; }

    public Person Creator { get; set; }

}

如您所见,每个人可以有多个任务。但是(!)该任务还有一个创建者,它是一个人。

我希望使用 entity framework 的添加迁移创建的工作项 table 有两个外键。一个使工作项可以归入 Person 的 WorkItems 集合,另一个指向工作项的创建者。如下图所示:

这似乎不是一个奇怪的场景,但它给我带来了很多问题。

如果您只是尝试使用 add-migration 创建数据库 tables,WorkItem 将按以下方式创建:

            CreateTable(
            "dbo.WorkItems",
            c => new
                {
                    Id = c.Guid(nullable: false),
                    Description = c.String(),
                    Creator_Id = c.Guid(),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.People", t => t.Creator_Id)
            .Index(t => t.Creator_Id);

如您所见,这里没有任何东西可以使 Person 成为其工作项的所有者。如果我删除 Creator 属性 它会按预期工作。当 class 是所有者时,引用 class 似乎有问题。

为什么这不能开箱即用?修复它的最佳方法是什么?导航属性?流利API?

这看起来像是一对多的关系,所以你的 Tasks 属性 应该是 ICollection<WorkItem>,你需要更新你的两个 classes.

你的 Person class 会是这样的:

public class Person
{
    public Guid Id { get; set; }

    public string Name { get; set; }

    public ICollection<WorkItem> Tasks { get; set; }
}

并且您还需要修改 WorkItem class 以引用创建 WorkItemPerson 实例,因此 WorkItem class 会像:

public class WorkItem
{
    public Guid Id { get; set; }

    public string Description { get; set; }

    [ForeignKey("Person")]
    public Guid WorkItemCreatorId{ get; set; }

    public Person Creator { get; set; }

}

现在这应该会在迁移中生成正确的 sql。

有关Entity Framework一对多关系的更多信息,请a look here

希望对你有用。

在 DbContext.OnModelCreating 中使用此配置配置您的实体(或者更好的是,添加单独的实体配置):

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
   modelBuilder.Entity<Person>().HasMany(p => p.WorkItems).WithMany();
   modelBuilder.Entity<WorkItem>().HasRequired(t => t.Creator).WithMany().WillCascadeOnDelete(false);
 }

这将为 Person 创建一个 table,为 WorkItem 创建另一个 table,再创建一个以支持 Person 和 WorkItem 之间的多对多关系。它还会在 WorkItem 中创建一个单独的 FK 来引用 Person:

我无法完全理解你的问题。我知道每个人都可以有多个任务,但我不确定一个任务是只能分配给一个人还是多个人。如果你只想要一对多的关系,使用这个配置:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
   modelBuilder.Entity<Person>().HasMany(p => p.WorkItems).WithOptional();
   modelBuilder.Entity<WorkItem>().HasRequired(t => t.Creator).WithMany().WillCascadeOnDelete(false);
 }

这只会创建两个 table,并且在 WorkItem 中创建两个 FK-s 来引用 Person table;一个用于 Creator,一个用于 EF 可以将 Person 中的引用连接到 WorkItems: