Entity Framework 核心 3.0 - 创建 self-referencing 多对多关系
Entity Framework Core 3.0 - Creating a self-referencing many to many relationship
所以这是我的问题...我要创建的是 self-referencing 多对多关系。基本上这是我的模型。
public class InformationSystem
{
public InformationSystem()
{
Systems = new HashSet<InformationSystem>();
ParentSystems = new HashSet<InformationSystem>();
}
[Key()]
public int InformationSystemID { get; set; }
public string InformationSystemName { get; set; }
//Navigation properties
public virtual ICollection<InformationSystem> Systems { get; set; }
public virtual ICollection<InformationSystem> ParentSystems { get; set; }
}
一个系统可以有很多 parent,一个 parent 可以有很多 children。我知道如何做一个 self-referencing 实体,其中许多 children 可以有一个 parent。让我绊倒的是多对多的部分。下面是我的 DbContext。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<InformationSystem>(entity =>
{
entity
.HasMany(e => e.ParentSystems)
.WithMany(e => e.Systems)
.OnDelete(DeleteBehavior.Restrict);
});
但是在我的 DbContext 上,我收到一个错误,指出 .WithMany 不包含接受类型集合输入的 with many 的定义。我知道当代码首先创建迁移并更新数据库时,基本上需要构建的是 link table。 link table 我认为会有两列并且没有键。一列是 InformationSystemID,一列是 ParentInformationSystemID。两者都是外键。我也知道,为了使其正常工作,应该限制删除行为,以便如果在 link table 中删除或更新条目,则该更改不会级联(并创建循环) .有人可以指出我需要做什么才能让 EF Core 3 正确执行此操作的正确方向吗?如果我必须自己创建一个 link table,我会怎么做呢?我需要在我的 DbContext 中做什么?我知道 link table 看起来像这样:
我将不胜感激。
public class InfoSysToParentInfoSys
{
public int InfoSysID;
public virtual InformationSystem InfoSys;
public int ParentInfoSysID;
public virtual InformationSystem ParentInfoSys;
}
在 EF Core 中,有必要在模型中包含一个实体以
表示 M:N 关系中的联接 table,然后将导航属性添加到
指向连接实体的多对多关系的一侧。
新的tableS:
public class InformationSystem
{
public InformationSystem()
{
}
[Key()]
public virtual int InformationSystemID { get; set; }
public virtual string InformationSystemName { get; set; }
public virtual ICollection<InformationSystemRelation> Systems { get; set; }
public virtual ICollection<InformationSystemRelation> ParentSystems { get; set; }
}
public class InformationSystemRelation
{
public int ParentId { get; set; }
public InformationSystem Parent { get; set; }
public int ChildId { get; set; }
public InformationSystem Child { get; set; }
}
映射:
modelBuilder.Entity<InformationSystemRelation>()
.HasKey(x => new { x.ParentId, x.ChildId });
modelBuilder.Entity<InformationSystemRelation>()
.HasOne(x => x.Parent)
.WithMany(x => x.Systems)
.HasForeignKey(x => x.ParentId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<InformationSystemRelation>()
.HasOne(x => x.Child)
.WithMany(x => x.ParentSystems)
.HasForeignKey(x => x.ChildId)
.OnDelete(DeleteBehavior.Restrict);
整个样本:
class Program
{
static void Main(string[] args)
{
var db = new MyDbContext();
var is1 = new InformationSystem() { InformationSystemName = "is1" };
var is2 = new InformationSystem() { InformationSystemName = "is2" };
var is3 = new InformationSystem() { InformationSystemName = "is3" };
var is4 = new InformationSystem() { InformationSystemName = "is4" };
db.InformationSystems.Add(is1);
db.InformationSystems.Add(is2);
db.InformationSystems.Add(is3);
db.InformationSystems.Add(is4);
db.SaveChanges();
var r1 = new InformationSystemRelation() { ParentId = 1, ChildId = 2 };
var r2 = new InformationSystemRelation() { ParentId = 1, ChildId = 3 };
var r3 = new InformationSystemRelation() { ParentId = 4, ChildId = 2 };
var r4 = new InformationSystemRelation() { ParentId = 2, ChildId = 3 };
var r5 = new InformationSystemRelation() { ParentId = 2, ChildId = 4 };
db.InformationSystemRelations.Add(r1);
db.InformationSystemRelations.Add(r2);
db.InformationSystemRelations.Add(r3);
db.InformationSystemRelations.Add(r4);
db.InformationSystemRelations.Add(r5);
db.SaveChanges();
var o2 = db.InformationSystems.Include(x => x.Systems).Include(x => x.ParentSystems).Single(x => x.InformationSystemID == 2);
}
}
public class InformationSystem
{
public InformationSystem()
{
}
[Key()]
public virtual int InformationSystemID { get; set; }
public virtual string InformationSystemName { get; set; }
public virtual ICollection<InformationSystemRelation> Systems { get; set; }
public virtual ICollection<InformationSystemRelation> ParentSystems { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<InformationSystem> InformationSystems { get; set; }
public DbSet<InformationSystemRelation> InformationSystemRelations { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<InformationSystem>(entity =>
{
modelBuilder.Entity<InformationSystemRelation>()
.HasKey(x => new { x.ParentId, x.ChildId });
modelBuilder.Entity<InformationSystemRelation>()
.HasOne(x => x.Parent)
.WithMany(x => x.Systems)
.HasForeignKey(x => x.ParentId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<InformationSystemRelation>()
.HasOne(x => x.Child)
.WithMany(x => x.ParentSystems)
.HasForeignKey(x => x.ChildId)
.OnDelete(DeleteBehavior.Restrict);
});
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("data source=(local)\SQLEXPRESS;Initial catalog=Test;Integrated security=SSPI");
base.OnConfiguring(optionsBuilder);
}
}
public class InformationSystemRelation
{
public int ParentId { get; set; }
public InformationSystem Parent { get; set; }
public int ChildId { get; set; }
public InformationSystem Child { get; set; }
}
所以这是我的问题...我要创建的是 self-referencing 多对多关系。基本上这是我的模型。
public class InformationSystem
{
public InformationSystem()
{
Systems = new HashSet<InformationSystem>();
ParentSystems = new HashSet<InformationSystem>();
}
[Key()]
public int InformationSystemID { get; set; }
public string InformationSystemName { get; set; }
//Navigation properties
public virtual ICollection<InformationSystem> Systems { get; set; }
public virtual ICollection<InformationSystem> ParentSystems { get; set; }
}
一个系统可以有很多 parent,一个 parent 可以有很多 children。我知道如何做一个 self-referencing 实体,其中许多 children 可以有一个 parent。让我绊倒的是多对多的部分。下面是我的 DbContext。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<InformationSystem>(entity =>
{
entity
.HasMany(e => e.ParentSystems)
.WithMany(e => e.Systems)
.OnDelete(DeleteBehavior.Restrict);
});
但是在我的 DbContext 上,我收到一个错误,指出 .WithMany 不包含接受类型集合输入的 with many 的定义。我知道当代码首先创建迁移并更新数据库时,基本上需要构建的是 link table。 link table 我认为会有两列并且没有键。一列是 InformationSystemID,一列是 ParentInformationSystemID。两者都是外键。我也知道,为了使其正常工作,应该限制删除行为,以便如果在 link table 中删除或更新条目,则该更改不会级联(并创建循环) .有人可以指出我需要做什么才能让 EF Core 3 正确执行此操作的正确方向吗?如果我必须自己创建一个 link table,我会怎么做呢?我需要在我的 DbContext 中做什么?我知道 link table 看起来像这样:
我将不胜感激。
public class InfoSysToParentInfoSys
{
public int InfoSysID;
public virtual InformationSystem InfoSys;
public int ParentInfoSysID;
public virtual InformationSystem ParentInfoSys;
}
在 EF Core 中,有必要在模型中包含一个实体以 表示 M:N 关系中的联接 table,然后将导航属性添加到 指向连接实体的多对多关系的一侧。
新的tableS:
public class InformationSystem
{
public InformationSystem()
{
}
[Key()]
public virtual int InformationSystemID { get; set; }
public virtual string InformationSystemName { get; set; }
public virtual ICollection<InformationSystemRelation> Systems { get; set; }
public virtual ICollection<InformationSystemRelation> ParentSystems { get; set; }
}
public class InformationSystemRelation
{
public int ParentId { get; set; }
public InformationSystem Parent { get; set; }
public int ChildId { get; set; }
public InformationSystem Child { get; set; }
}
映射:
modelBuilder.Entity<InformationSystemRelation>()
.HasKey(x => new { x.ParentId, x.ChildId });
modelBuilder.Entity<InformationSystemRelation>()
.HasOne(x => x.Parent)
.WithMany(x => x.Systems)
.HasForeignKey(x => x.ParentId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<InformationSystemRelation>()
.HasOne(x => x.Child)
.WithMany(x => x.ParentSystems)
.HasForeignKey(x => x.ChildId)
.OnDelete(DeleteBehavior.Restrict);
整个样本:
class Program
{
static void Main(string[] args)
{
var db = new MyDbContext();
var is1 = new InformationSystem() { InformationSystemName = "is1" };
var is2 = new InformationSystem() { InformationSystemName = "is2" };
var is3 = new InformationSystem() { InformationSystemName = "is3" };
var is4 = new InformationSystem() { InformationSystemName = "is4" };
db.InformationSystems.Add(is1);
db.InformationSystems.Add(is2);
db.InformationSystems.Add(is3);
db.InformationSystems.Add(is4);
db.SaveChanges();
var r1 = new InformationSystemRelation() { ParentId = 1, ChildId = 2 };
var r2 = new InformationSystemRelation() { ParentId = 1, ChildId = 3 };
var r3 = new InformationSystemRelation() { ParentId = 4, ChildId = 2 };
var r4 = new InformationSystemRelation() { ParentId = 2, ChildId = 3 };
var r5 = new InformationSystemRelation() { ParentId = 2, ChildId = 4 };
db.InformationSystemRelations.Add(r1);
db.InformationSystemRelations.Add(r2);
db.InformationSystemRelations.Add(r3);
db.InformationSystemRelations.Add(r4);
db.InformationSystemRelations.Add(r5);
db.SaveChanges();
var o2 = db.InformationSystems.Include(x => x.Systems).Include(x => x.ParentSystems).Single(x => x.InformationSystemID == 2);
}
}
public class InformationSystem
{
public InformationSystem()
{
}
[Key()]
public virtual int InformationSystemID { get; set; }
public virtual string InformationSystemName { get; set; }
public virtual ICollection<InformationSystemRelation> Systems { get; set; }
public virtual ICollection<InformationSystemRelation> ParentSystems { get; set; }
}
public class MyDbContext : DbContext
{
public DbSet<InformationSystem> InformationSystems { get; set; }
public DbSet<InformationSystemRelation> InformationSystemRelations { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<InformationSystem>(entity =>
{
modelBuilder.Entity<InformationSystemRelation>()
.HasKey(x => new { x.ParentId, x.ChildId });
modelBuilder.Entity<InformationSystemRelation>()
.HasOne(x => x.Parent)
.WithMany(x => x.Systems)
.HasForeignKey(x => x.ParentId)
.OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<InformationSystemRelation>()
.HasOne(x => x.Child)
.WithMany(x => x.ParentSystems)
.HasForeignKey(x => x.ChildId)
.OnDelete(DeleteBehavior.Restrict);
});
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("data source=(local)\SQLEXPRESS;Initial catalog=Test;Integrated security=SSPI");
base.OnConfiguring(optionsBuilder);
}
}
public class InformationSystemRelation
{
public int ParentId { get; set; }
public InformationSystem Parent { get; set; }
public int ChildId { get; set; }
public InformationSystem Child { get; set; }
}