Elias Hridoy
Elias Hridoy

Reputation: 39

EF core eager loading - loads same data multiple times

I have a product table and a category table. Where all the products have a FK-categoryId. How to stop loading data multiple times? Like this:

Class:

 public partial class Product
    {
        public Product()
        {
            OrderItem = new HashSet<OrderItem>();
            ProductPictureMapping = new HashSet<ProductPictureMapping>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public int CategoryId { get; set; }
        public virtual Category Category { get; set; }
 }


public partial class Category
    {
        public Category()
        {
            Product = new HashSet<Product>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Product> Product { get; set; }
    }

Controller method:

   var allProduct = _context.Product
                                    .Include("Category")
                                    .ToListAsync();

Output:

It returns a Product then a Category then all Product under Category Note that I already disable looping using this in startup.csNewtonsoft.Json.ReferenceLoopHandling.Ignore;

[{
    "id": 1,
    "name": "Redmi Note 7",
    "category": {
      "id": 2,
      "name": "Mobile",
      "product": [
        {
          "id": 2,
          "name": "Mi Note 9",
          "category":null
        }]
      },
{
     
     "id": 2,
     "name": "Mi Note 9",
      "category": {
              "id": 1,
              "name": "Redmi Note 7",
             "category":null
       }
}]

Upvotes: 0

Views: 274

Answers (1)

atiyar
atiyar

Reputation: 8338

You can use Data Transfer Object (DTO) models to get rid of the navigation properties which create those reference loops.

Create the following two DTO models -

public class ProductDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
    public CategoryDTO Category { get; set; }
}

public class CategoryDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Then use projection in your query like -

var allProduct = dbCtx.Products
        .Select(p => new ProductDTO
        {
            Id = p.Id,
            Name = p.Name,
            Category = new CategoryDTO
            {
                Id = p.Category.Id,
                Name = p.Category.Name
            }
        });

If you don't need typed objects in your query result, you can do the same thing without creating any DTO models and using anonymous types in your projection like -

var allProduct = dbCtx.Products
        .Select(p => new
        {
            Id = p.Id,
            Name = p.Name,
            Category = new
            {
                Id = p.Category.Id,
                Name = p.Category.Name
            }
        });

Upvotes: 1

Related Questions