Search code examples
asp.net-coremany-to-manyentity-framework-core

How to create custom navigation property on EF Core


I m using .NET Core 2.0. I wrote, a lot for navigation property I know that does not support automatic lazy loading on EF Core at this time. I m using Microsoft approach to create navigation property. I`m trying to create a many-to-many relationship.

First create manually mapping table that is also included in ApplicationDbContext like new DbSet

public class ProductCategory
    {
        [Key]
        public int ProductId { get; set; }
        [ForeignKey("ProductId")]
        public virtual Product Product { get; set; }

        [Key]
        public int CategoryId { get; set; }
        [ForeignKey("CategoryId")]
        public virtual Category Category { get; set; }
    }

   public class Product
    {
        public int Id { get; set; }
        public virtual ICollection<ProductCategory> ProductCategory { get; set; 
    }

   public class Category
    {
        public int Id { get; set; }
        public virtual ICollection<ProductCategory> ProductCategory { get; set; 
    }

In OnModelCreating class

            builder.Entity<ProductCategory>()
            .HasKey(x => new { x.CategoryId, x.ProductId });

            builder.Entity<ProductCategory>()
                .HasOne(x => x.Product)
                .WithMany(x => x.ProductCategory)
            .HasForeignKey(x => x.ProductId);

            builder.Entity<ProductCategory>()
               .HasOne(x => x.Category)
               .WithMany(x => x.ProductCategory)
            .HasForeignKey(x => x.CategoryId);

When adding a new object in mapping table.

var productCategory = new ProductCategory
            {
                CategoryId = 1,
                ProductId = 1
            };

            db.ProductCategory.Add(productCategory);
            db.SaveChanges();

Item is added successfully, after that try to access Product or Category to test navigation property but receives only the current class in the mapping table.You can see the example when I`m trying to access product from category class:

model.Categories = this._categoryService
                .All()
                .Include(x => x.ProductCategory)
                .ToList();

many-to-many-error-ef7

Product class is null?


Solution

  • It's because including navigation property automatically includes the inverse navigation property, but nothing more. You need to specifically ask for that using ThenInclude.

    Assuming All method returns IQueryable<Category>, something like this:

    model.Categories = this._categoryService
                    .All()
                    .Include(x => x.ProductCategory)
                        .ThenInclude(x => x.Product)
                    .ToList();
    

    Note that this will also automatically include (load) the ProductCategory collection property of the Product entity.