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

EF Core:如何避免Include导致返回数据库行数激增?

解决Telerik Grid关联数据查询行数过多的问题

针对你遇到的Include导致数据库返回大量重复行、同时需要保留IQueryable<T>支持分页筛选的问题,有两种实用方案:

1. 投影到DTO(推荐)

直接通过Select构造只包含网格所需字段的DTO(数据传输对象),EF Core会生成高效的SQL,避免笛卡尔积导致的重复行,同时保持IQueryable特性,让分页、筛选逻辑推送到数据库执行。

示例代码:

首先定义适配网格的DTO:

public class TransactionGridDto
{
    public int Id { get; set; }
    public decimal Amount { get; set; }
    public string SourceName { get; set; } // 交易来源名称
    public string TerminalId { get; set; } // 支付终端ID
    public string LessorName { get; set; } // 终端出租方名称
}

然后构造查询:

// 替换原有的Include写法,直接投影到DTO
var query = dbContext.Transactions
    .Select(t => new TransactionGridDto
    {
        Id = t.Id,
        Amount = t.Amount,
        SourceName = t.Source.Name,
        TerminalId = t.Terminal.TerminalId,
        LessorName = t.Terminal.Lessor.Name
    });

将这个IQueryable<TransactionGridDto>绑定到Telerik Grid,网格的分页、筛选、排序会自动转换为对应的SQL查询,数据库仅返回分页所需的30行数据,且每行只包含你指定的字段,没有冗余重复。

如果关联的是集合型数据(比如一个交易有多条明细),同样可以在投影中处理:

public class TransactionGridDto
{
    // 基础字段...
    public List<TransactionDetailDto> Details { get; set; }
}

public class TransactionDetailDto
{
    public int LineId { get; set; }
    public int Quantity { get; set; }
}

var query = dbContext.Transactions
    .Select(t => new TransactionGridDto
    {
        Id = t.Id,
        Amount = t.Amount,
        // 投影集合数据
        Details = t.Details.Select(d => new TransactionDetailDto
        {
            LineId = d.Id,
            Quantity = d.Quantity
        }).ToList()
    });

EF Core 3.0+支持这种集合投影,会通过子查询获取集合数据,不会重复主表的交易行。

2. 使用AsSplitQuery拆分查询

如果不想定义DTO,希望直接使用实体类,可以用EF Core的AsSplitQuery()方法,将多Include的查询拆分为多个独立的SQL查询,避免笛卡尔积导致的重复行。

示例代码:

var query = dbContext.Transactions
    .Include(t => t.Source)
    .Include(t => t.Terminal)
    .Include(t => t.Terminal.Lessor)
    .AsSplitQuery();

执行后,SQL Server会生成多个查询:

  • 第一个查询获取分页的30条交易数据
  • 后续查询分别获取这30条交易对应的来源、终端、出租方数据

总返回行数会远少于笛卡尔积的结果(比如30+30+30+30=120行,而非笛卡尔积的30*N行),EF Core会自动将这些查询的结果合并为实体对象,同时保持IQueryable的分页、筛选能力。

网格绑定注意事项

无论是用DTO还是实体类,只要绑定的是IQueryable<T>,Telerik Grid的分页、筛选、排序都会自动推送到数据库执行,无需手动实现逻辑。只需在网格列配置中指定对应的字段即可,比如:

<TelerikGrid Data="@GridQuery" Pageable="true" PageSize="30" Filterable="true" Sortable="true">
    <GridColumns>
        <GridColumn Field="@nameof(TransactionGridDto.Id)" Title="交易ID" />
        <GridColumn Field="@nameof(TransactionGridDto.Amount)" Title="金额" />
        <GridColumn Field="@nameof(TransactionGridDto.SourceName)" Title="交易来源" />
    </GridColumns>
</TelerikGrid>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 05:35:02