EF Core 中具有 TPH 继承的多对多

Many-to-many with TPH inheritance in EF Core

如果连接 table 的一侧是 table 中的派生 class,我在使用 EF 核心设置多对多连接 table 时遇到问题=]-每个层次结构设置。

设置如下:

class Chore
{
    Guid Id;
}

class LaundryChore : Chore
{
    // PROBLEMATIC
    List<Clothing> ManyClothing;   
}

class FoldingChore : Chore
{
    Clothing SingleClothing;   
}

class Clothing
{
    Guid Id;
    
    // PROBLEMATIC
    List<Chore> Chores;
}

我已经为 TPH 设置了鉴别器并且一切正常。如果 ManyClothing 字段在 Chore class 上,那么我可以这样做:

builder.Entity<Clothing>().HasMany(clothing => clothing.Chores)
    .WithMany(chore => chore.ManyClothing);

这按预期工作。

但是由于 ManyClothing 字段在 LaundryChore class 上,我会收到上面的 DNE 错误。

我试过换方向:

builder.Entity<LaundryChore>().HasMany(chore => clothing.ManyClothing)
    .WithMany(clothing => clothing.Chores);

我得到一个转换错误:

Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.IEnumerable'

如果我改为:

class Clothing
{
    Guid Id;

    List<LaundryChore> Chores;
}

然后我得到的错误是:

The filter expression ... cannot be specified for entity type 'LaundryChore'. A filter may only be applied to the root entity type 'Chore'

任何指导将不胜感激 - 谢谢!

A navigation properties can only participate in a single relationship.

不是限制类型,而是关系限制。例如,如果您只有 ChoreClothing 类 :

public class Chore
{
    public int Id { get; set; }
    public List<Clothing> ManyClothingToLaundry { get; set; }
    public Clothing SingleClothingToFolding { get; set; }
}

public class Clothing
{
    public int Id { get; set; }
    public List<Chore> Chores { get; set; }
}

现在,您想为服装添加杂务:

clothing.Chores.Add(chore);

这会给洗衣或叠衣服增加麻烦吗? EF Core 在这种情况下无法知道。

在您的特定情况下,EF Core 可以从类型中检测到关系,但未实现此功能。

如果 Clothing 有两个不同的关系,那么 Clothing 需要两个导航属性:

public class Clothing
{
    public int Id { get; set; }
    public List<Chore> FoldingChores { get; set; }
    public List<Chore> LaundryChores { get; set; }
    public IEnumerable<Chore> Chores => FoldingChores.Union(LaundryChores);
}

...

protected override void OnModelCreating(ModelBuilder builder)
{
    ...
    builder.Entity<Clothing>().Ignore(c => c.Chores);
    builder.Entity<Clothing>()
        .HasMany<LaundryChore>(nameof(Clothing.LaundryChores))
        .WithMany(chore => chore.ManyClothing);
    builder.Entity<Clothing>()
        .HasMany<FoldingChore>(nameof(Clothing.FoldingChores))
        .WithOne(chore => chore.SingleClothing);
}

Clothing.FoldingChores是例子中基础实体Chore的集合,但也可以直接是结局类型FoldingChore的集合。与 Clothing.LaundryChores 相同:

public class Clothing
{
    public int Id { get; set; }
    public List<FoldingChore> FoldingChores { get; set; }
    public List<LaundryChore> LaundryChores { get; set; }
    public IEnumerable<Chore> Chores => FoldingChores.Cast<Chore>().Union(LaundryChores.Cast<Chore>());
}