EF Core GetNavigations ignoring a collection

Viewed 190

I have the following structure:

public class Message
{
    ...
    public MessageType MessageType { get; set; }
    public ICollection<Product> Products { get; set; }
    public ICollection<Product> ProductsWhereThisIsDefaultCompletedSale { get; set; }
}

public class Product
{
    ...
    public Guid? DefaultCompletedSaleMessageId { get; set; }
    public Message DefaultCompletedSaleMessage { get; set; }
    public ICollection<Message> Messages { get; set; }
}

public MessageType {...}

And the mapper:

EntityTypeBuilder<Product> entityBuilder;
entityBuilder
    .HasMany(p => p.Messages)
    .WithMany(m => m.Products);
entityBuilder
    .HasOne(p => p.DefaultCompletedSaleMessage)
    .WithMany(m => m.ProductsWhereThisIsDefaultCompletedSale)
    .OnDelete(Microsoft.EntityFrameworkCore.DeleteBehavior.NoAction);

And this is working nicely with the database (at least I think so...). When I add a new product to the Messages collection it's added to the ProductsMessages relationships' table. The records are loaded when I eager load them (Include(...)).

The problem is, I'm trying to get all navigation properties to auto include them on certain specific scenarios. But that's not working properly. When I run entityType.GetNavigations() (doc) on Message it doesn't return Products, it only returns the other two navigation properties, ProductsWhereThisIsDefaultCompletedSale and MessageType:

enter image description here

Any ideas on what am I doing incorrectly?

Please let me know if you need more information. I'm on .NET5. Thanks!

1 Answers

It's because these are the so called skip navigations, introduced in EF Core 5.0 and used for implementing many-to-many with implicit join entity.

They are represented by ISkipNavigation interface, which for some design decision does not inherit INavigation interface returned by the GetNavigations method, so they are retrieved with separate method called GetSkipNavigations.

But both INavigation and ISkipNavigation share a common interface INavigationBase, so if its properties/methods are enough for what are you trying to do with them, you can get both type of collection navigations with something like this (needs using Microsoft.EntityFrameworkCore.Metadata;):

var allNavigations = entityType.GetNavigations()
    .Concat<INavigationBase>(entityType.GetSkipNavigations());
Related