簡體   English   中英

在 ef 核心中以多對多關系直接訪問相關數據(並跳過鏈接類)

[英]accessing related data directly (and skipping linking class) in many to many relation in ef core

假設我想要一個 class A和很多B和很多A 我可以通過創建 class AB ,將ICollection<AB> ABs字段添加到AB類,然后通過 class AABs屬性訪問B來實現這一點。 這有效。 但我想知道有沒有辦法直接從 class A訪問相關的B數據,而不是通過ABs屬性。

我會想出幾種方法來做到這一點(我都沒有設法開始工作):

  • public ICollection<B> Bs => this.ABs.Select(item => item.B).ToList(); ,但它沒有,我有 null 異常,即使我確實在此上下文中包含ABsBs context.As.Include(item => item.ABs).ThenInclude(item => item.B); .

  • ef core的流利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)
      );
    }
  }
}

使用第一種方法,我得到System.ArgumentNullException: 'Value cannot be null. (Parameter 'source')' System.ArgumentNullException: 'Value cannot be null. (Parameter 'source')'錯誤,即使我IncludeThenInclude所有相同的字段。

我意識到AB class 必須以任何方式保持不變,但是這種配置是否可以實現,以及這樣做的正確方法是什么。

該異常是由 EF 對默認映射約定的推斷引起的。 也就是說,在構建實體 model 時,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);

當然,即使沒有例外,也應該取消映射該屬性,因為您不希望它反映在數據庫關聯中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM