Entity Framework Core 3.0 - создание самосвязанных отношений «многие ко многим» - PullRequest
0 голосов
/ 10 апреля 2020

Итак, вот моя проблема ... то, что я пытаюсь создать, это самоотносящиеся отношения многих ко многим. В основном, вот моя модель.

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; }
}

Идея в том, что в системе может быть много родителей, а у родителя может быть много детей. Я знаю, как создать самореферентную сущность, где у многих детей может быть один родитель. То, что сбивает меня с толку, это много-много. Ниже мой 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 не содержит определения для многих, которые приняли бы ввод типа коллекции. Я знаю, что в основном необходимо создать таблицу ссылок, когда код сначала создает миграцию и обновляет базу данных. Таблица ссылок, я думаю, будет иметь два столбца и без ключа. Один столбец будет InformationSystemID, а другой - ParentInformationSystemID. Оба будут внешние ключи. Я также знаю, что для правильной работы поведение удаления должно быть ограничено, чтобы в случае удаления или обновления записи в таблице ссылок это изменение не каскадно (и создает al oop). Может кто-нибудь указать мне правильное направление, что мне нужно сделать, чтобы EF Core 3 сделал это правильно? Если бы мне пришлось самому создать таблицу ссылок, как бы я go сделал это? И что мне нужно сделать в моем DbContext? Я знаю, что таблица ссылок будет выглядеть примерно так:
Я был бы очень признателен.

public class InfoSysToParentInfoSys
{
  public int InfoSysID;
  public virtual InformationSystem InfoSys;

  public int ParentInfoSysID;
  public virtual InformationSystem ParentInfoSys;
}

1 Ответ

0 голосов
/ 10 апреля 2020

В EF Core необходимо включить объект в модель для представления таблицы соединения в отношении M: N, а затем добавить свойства навигации по обе стороны от отношений «многие ко многим», которые указывают на объект объединения. .

Новые таблицы S:

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; }
}
...