прямой доступ к связанным данным (и пропуск класса связывания) во многих отношениях ко многим в ядре ef - PullRequest
1 голос
/ 05 ноября 2019

Допустим, я хочу иметь класс A со многими B со многими A;Я могу добиться этого, создав класс AB, добавив поле ICollection<AB> ABs к классам A и B, а затем получив доступ к свойству B через ABs класса A. И это работает. Но мне было интересно, есть ли способ получить доступ к связанным B данным непосредственно из класса A, вместо того, чтобы делать это через свойство ABs.

Я бы представил несколько способов сделать это (ни один изкоторый мне удалось заставить работать):

  • public ICollection<B> Bs => this.ABs.Select(item => item.B).ToList();, но это не так, у меня есть нулевое исключение в этом, хотя я включаю ABs и Bs с этим context.As.Include(item => item.ABs).ThenInclude(item => item.B);.

  • ef текущие API ядра (не знаю, как это сделать)

using Microsoft.EntityFrameworkCore;
using System;
using Context;

namespace ConsoleApp1 {
  class Program
  {
    static void Main(string[] args)
    {
      using var context = new ZContext();
      context.Database.EnsureDeleted();
      context.Database.EnsureCreated();
      var A = context.As.Include(item => item.ABs).ThenInclude(item => item.B);
      foreach (var a in A) {
        Console.WriteLine(a.Bs);
      }

      return;
    }
  }
}

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Context
{
  public class IDed
  {
    #region Constructors
    public IDed()
    {
      ID = Guid.NewGuid();
    } 
    #endregion

    public Guid ID { get; set; }
  }
  public class A : IDed
  {
    public ICollection<AB> ABs { get; set; }
    public ICollection<B> Bs { 
      get {
        return ABs.Select(item => item.B).ToList();
      }
    }
  }
  public class B : IDed
  {
    public ICollection<AB> ABs { get; set; }
  }
  public class AB
  {
    #region Constructors
    public AB()
    {

    }
    public AB(A a, B b)
    {
      this.AID = a.ID;
      this.BID = b.ID;
    } 
    #endregion

    public A A { get; set; } public Guid AID { get; set; }
    public B B { get; set; } public Guid BID { get; set; }
  }
  public class ZContext : DbContext
  {
    public DbSet<A> As { get; set; }
    public DbSet<B> Bs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      optionsBuilder.UseSqlite("Data Source=111.db3");
    }

    protected override void OnModelCreating(ModelBuilder mb)
    {
      #region Keys
      mb.Entity<AB>().HasKey(item => new { item.AID, item.BID });
      #endregion
      #region Relations
      // ???
      #endregion
      var a1 = new A();
      var a2 = new A();
      mb.Entity<A>().HasData(a1, a2);

      var b1 = new B(); 
      var b2 = new B();
      mb.Entity<B>().HasData(b1, b2);
      mb.Entity<AB>().HasData(
        new AB(a1, b1),
        new AB(a1, b2),
        new AB(a2, b1),
        new AB(a2, b2)
      );
    }
  }
}

С 1-м методом я получаю *Ошибка 1034 *, хотя у меня Include и ThenInclude все одинаковые поля.

Я понимаю, что класс AB должен остаться каким-либо образом, но будет ли такая конфигурация возможной, и чтобудет правильным способом сделать это.

1 Ответ

1 голос
/ 05 ноября 2019

Исключение вызвано выводом EF соглашений об отображении по умолчанию. То есть при построении модели сущности EF сталкивается со свойством A.Bs и пытается найти для него отображение базы данных. Именно в этот самый ранний момент происходит исключение. Как только вы это узнаете, исправить это легко: просто снимите отображение свойства:

[NotMapped]
public ICollection<B> Bs
{
    get
    {
        return ABs.Select(item => item.B).ToList();
    }
}

или

protected override void OnModelCreating(ModelBuilder mb)
{
    ...
    mb.Entity<A>().Ignore(a => a.Bs);

Конечно, даже без исключения свойство должно быть не отображено, потому что вы нене хочу, чтобы это было отражено в ассоциации базы данных.

...