如何使用Entity Framework Code First创建一个表,其中两个外键指向同一个表

时间:2017-11-24 19:11:46

标签: c# sql-server entity-framework-6 ef-code-first

我有以下类,我首先尝试使用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; }

}

正如你所看到的,每个人都可以完成许多任务。但是(!)任务也有一个人的创造者。

我希望使用实体框架的add-migration创建的workitem表有两个外键。一个是工作项可以与Person的WorkItems集合相混合,另一个指向Workitem的创建者。如下图所示:

enter image description here

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

如果您只是尝试使用add-migration创建数据库表,则可以通过以下方式创建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);

正如您所看到的,没有任何内容可以使此人成为其工作项的所有者。如果我删除了Creator属性,它会按预期工作。当该类是所有者时,引用类似乎存在问题。

为什么这不是开箱即用的工具,解决问题的最佳方法是什么?导航属性?流畅的API?

2 个答案:

答案 0 :(得分:2)

在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创建一个表,为WorkItem创建另一个表,另一个用于支持Person和WorkItem之间的多对多关系。它还将在WorkItem中创建一个单独的FK来引用Person:

enter image description here

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

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

这只创建了两个表,而在WorkItem中有两个FK-s引用Person表;一个用于创建者,另一个用于EF可以将Person中的引用连接到WorkItems:

enter image description here

答案 1 :(得分:0)

这看起来像是一对多的关系,因此您的Tasks属性应为ICollection<WorkItem>,您需要更新这两个类。

您的Person课程就像:

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

    public string Name { get; set; }

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

并且您还需要修改WorkItem类以引用创建Person的{​​{1}}实例,因此WorkItem类将是:

WorkItem

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

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

希望它适合你。