Entity Framework Core 2.0 Select Query with many-to-many problem

.net asp.net-core entity-framework-core

Question

Below is the model.

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

class Categorization
{
    public int ProductId { get; set; }
    public Product Product { get; set; }

    public int CategoryId { get; set; }
    public Category Category { get; set; }
}

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

I am trying to list down all the Products and their Category as well. API Code as below

foreach (var product in _context.Products.ToList()){
    var categories = product.Categorization.Select(c => c.Category);
    ...     
}

When we call the Api, I get this error:

System.ArgumentNullException: Value cannot be null.
Parameter name: source
at System.Linq.Enumerable.Select[TSource,TResult](IEnumerable1 source, Func2 selector)

1
0
9/19/2018 7:00:06 PM

Accepted Answer

product.Categorization is null because it's not loaded. If you're expecting lazy loading to handle the load you must make the product.Categorization property virtual (along with the properties you wish to lazy load in the Categorization class, Category in this case)

Edit: in your example you should eager load the data using Include and ThenInclude as you know you need the data:

_context.Products
   .Include( p => p.Categorization )
   .ThenInclude( c => c.Category )
   .ToList()
1
9/19/2018 7:43:03 PM

Popular Answer

For querying all products and their categories, you could try Include and ThenInclude like below:

        public async Task<IActionResult> GetAllArticleAsync()
    {
        var articles = await _context.Articles
                               .Include(a => a.ArticleTags)
                               .ThenInclude(at => at.Tag)
                               .Select(a => new
                               {
                                   Id = a.Id,
                                   ArticleName = a.ArticleName,
                                   Tags = a.ArticleTags.Select(at => at.Tag).ToList()
                               })
                               .ToListAsync();
        return Ok(articles);
    }

For this way, you need to configure opt.SerializerSettings.ReferenceLoopHandling in Startup.cs like below:

        services.AddMvc()
                .AddJsonOptions(opt => opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

For a complete demo, refer EFCorePro



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow