首页 > 解决方案 > EF 核心急切加载 - 多次加载相同的数据

问题描述

我有一个产品表和一个类别表。所有产品都有一个 FK-categoryId。如何停止多次加载数据?像这样:

班级:

 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; }
    }

控制器方法:

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

输出:

它返回一个产品,然后是一个类别,然后是类别下的所有产品注意 ,我已经在 startup.cs Newtonsoft.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
       }
}]

标签: c#.netlinq.net-coreentity-framework-core

解决方案


您可以使用Data Transfer Object (DTO)模型来摆脱创建这些参考循环的导航属性。

创建以下两个 DTO 模型 -

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; }
}

然后在您的查询中使用投影,例如 -

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
            }
        });

如果您不需要在查询结果中键入对象,您可以在不创建任何 DTO 模型并在投影中使用匿名类型的情况下执行相同的操作,例如 -

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

推荐阅读