如何使用 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 以引用创建 WorkItem
的 Person
实例,因此 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:
我有以下 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 以引用创建 WorkItem
的 Person
实例,因此 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: