Reputation: 23
I am having trouble with setting up a many-to-many join table with EF core if one side of the join table is a derived class in table-per-hierarchy set up.
Here's the set up:
class Chore
{
Guid Id;
}
class LaundryChore : Chore
{
// PROBLEMATIC
List<Clothing> ManyClothing;
}
class FoldingChore : Chore
{
Clothing SingleClothing;
}
class Clothing
{
Guid Id;
// PROBLEMATIC
List<Chore> Chores;
}
I have the TPH set up with discriminator and that all works fine. IF the ManyClothing
field was on the Chore
class then I can just do:
builder.Entity<Clothing>().HasMany(clothing => clothing.Chores)
.WithMany(chore => chore.ManyClothing);
and this works as expected.
But since ManyClothing
field was on the LaundryChore
class, I would get DNE error with above.
I tried switching the direction:
builder.Entity<LaundryChore>().HasMany(chore => clothing.ManyClothing)
.WithMany(clothing => clothing.Chores);
and I get a casting error:
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.IEnumerable'
If I change to:
class Clothing
{
Guid Id;
List<LaundryChore> Chores;
}
Then the error I get is:
The filter expression ... cannot be specified for entity type 'LaundryChore'. A filter may only be applied to the root entity type 'Chore'
Any guidance would be appreciated - thanks!
Upvotes: 2
Views: 1326
Reputation: 7590
A navigation properties can only participate in a single relationship.
It isn't a limitation type, but a limitation by relation. For example, if you have only the Chore
and Clothing
classes :
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; }
}
Now, you want add a Chore to a Clothing :
clothing.Chores.Add(chore);
Do this add a chore to laundry or to folding? EF Core can't know in this case.
In your specific case, EF Core could detect the relationship from the type, but this functionality is not implemented.
If Clothing has two distinct relationship, then Clothing need two navigation properties :
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
is a collection of the base entity Chore
for the example, but it can be directly a collection of the finale type FoldingChore
. Idem with 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>());
}
Upvotes: 0