You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Entity Framework中正确使用.Include()关联多张表

问题:EF Core查询Item时关联获取SetContent及对应Set数据

现有三个EF Core模型类:

public class Set
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Code { get; set; }
    public DateTime? ReleaseDate { get; set; }
    public string Type { get; set; }
    public string? Series { get; set; }
    public string? Description { get; set; }

    public ICollection<SetContent> Content { get; set; }
}

public class SetContent
{
    public int Id { get; set; }
    public int SetId { get; set; }
    public string? SetCode { get; set; }
    public string? SetRarity { get; set; }
    public string? SetRarityCode { get; set; }
    public int ItemId { get; set; }
    public virtual Item Item { get; set; }
}

public class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Type { get; set; }
    public string Desc { get; set; }
    public string ImageBig { get; set; }
    public string ImageSmall { get; set; }

    public ICollection<SetContent> Sets { get; set; } = new List<SetContent>();
}

需求是在Item详情页中,查询Item时同时获取关联的SetContent数据,以及每个SetContent对应的Set数据,最终得到如下结构的DTO:

{
   "id": 0,
   "name": "string",
   "type": "string",
   "desc": "string",
   "imageBig": "string",
   "imageSmall": "string",
   "sets": [
   {
     "id": 0,
     "setId": 0,
     "setCode": "string",
     "setRarity": "string",
     "setRarityCode": "string",

     "SetName": "string",
     "ReleaseDate": "DateTime"
   }
   ]
}

之前尝试的两种查询方式均存在问题:

  • 仅通过Include(_c => _c.Sets)只能拿到SetContent数据,无法获取关联的Set信息
  • 手动加载Sets集合存在数据过时、引用循环空值的问题

解决方案

1. 补充模型导航属性(推荐)

在SetContent类中添加对Set的导航属性,让EF Core能识别完整的关联关系:

public class SetContent
{
    public int Id { get; set; }
    public int SetId { get; set; }
    public string? SetCode { get; set; }
    public string? SetRarity { get; set; }
    public string? SetRarityCode { get; set; }
    public int ItemId { get; set; }
    
    public virtual Item Item { get; set; }
    // 添加Set导航属性
    public virtual Set Set { get; set; }
}

2. 使用Include+ThenInclude加载多层关联数据

通过嵌套的Include和ThenInclude,一次性加载Item、关联的SetContent,以及每个SetContent对应的Set数据:

var item = await _context.Items
    .Include(i => i.Sets)
        .ThenInclude(sc => sc.Set) // 关联加载SetContent对应的Set实体
    .FirstOrDefaultAsync(i => i.Id == id);

3. 配置DTO映射(若使用AutoMapper)

在AutoMapper配置中,指定从SetContent和关联的Set中提取所需字段:

// 假设SetContent对应的DTO为SetContentDto
CreateMap<SetContent, SetContentDto>()
    .ForMember(dest => dest.SetName, opt => opt.MapFrom(src => src.Set.Name))
    .ForMember(dest => dest.ReleaseDate, opt => opt.MapFrom(src => src.Set.ReleaseDate));

CreateMap<Item, ItemReadOnlyDto>()
    .ForMember(dest => dest.sets, opt => opt.MapFrom(src => src.Sets));

4. 处理序列化引用循环(可选)

如果JSON序列化时出现引用循环错误,可在项目配置中忽略循环引用:

builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
    });

5. 直接投影构造DTO(高效替代方案)

无需加载完整实体,直接通过LINQ投影构造目标DTO,减少不必要的数据查询:

var itemDto = await _context.Items
    .Where(i => i.Id == id)
    .Select(i => new ItemReadOnlyDto
    {
        Id = i.Id,
        Name = i.Name,
        Type = i.Type,
        Desc = i.Desc,
        ImageBig = i.ImageBig,
        ImageSmall = i.ImageSmall,
        sets = i.Sets.Select(sc => new SetContentDto
        {
            Id = sc.Id,
            SetId = sc.SetId,
            SetCode = sc.SetCode,
            SetRarity = sc.SetRarity,
            SetRarityCode = sc.SetRarityCode,
            SetName = sc.Set.Name,
            ReleaseDate = sc.Set.ReleaseDate
        }).ToList()
    })
    .FirstOrDefaultAsync();

内容的提问来源于stack exchange,提问作者Avalari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:10:55