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

Entity Framework:单事务中无关联多表多查询无需指定实体用Select

将指定SQL转换为Entity Framework无实体模型的查询实现

需求背景

需要将以下SQL查询转换为Entity Framework代码:

select (select sum(paid) from table_a) Paid, (select count(*) from table_b) ct

尝试过如下写法,但因Entity Framework要求Select()必须基于实体模型而无法运行:

await ctx.Select(u => new
{
   Paid = ctx.table_a.Sum(i => i.paid),
   Ct = ctx.table_b.Count(i => i.key)
}).ToArrayAsync();

已排除两个方案:

  • 单独调用各查询(希望保持单事务)
  • 使用ExecuteSqlRawAsync或ExecuteSqlInterpolatedAsync(希望避免原生SQL)

解决方案

你可以通过构造虚拟单元素数据源来启动Select查询,既不依赖特定业务实体,又能在同一个数据库请求(事务)中完成多表聚合。

方法1:利用任意实体的Take(1)构造数据源

var result = await ctx.Set<object>()
                      .Take(1) // 仅构造单元素数据源,不会实际查询数据
                      .Select(_ => new 
                      {
                          Paid = ctx.table_a.Sum(i => i.paid),
                          Ct = ctx.table_b.Count(i => i.key)
                      })
                      .FirstOrDefaultAsync();

方法2:用FromSqlRaw构造常量数据源

var result = await ctx.FromSqlRaw("SELECT 1 AS Dummy")
                      .Select(_ => new 
                      {
                          Paid = ctx.table_a.Sum(i => i.paid),
                          Ct = ctx.table_b.Count(i => i.key)
                      })
                      .FirstOrDefaultAsync();

这两种写法最终生成的SQL与目标语句几乎一致,且整个操作会在同一事务中执行(若上下文已配置事务,或手动包裹using var transaction = await ctx.Database.BeginTransactionAsync())。

备选方案(EF Core 7+):用SqlQueryAsync映射匿名类型

若你的EF版本为Core 7及以上,可直接将原生SQL映射到匿名类型,相比ExecuteSqlRaw更简洁:

var result = await ctx.Database.SqlQueryAsync(new 
{
    Paid = default(decimal?), // 匹配sum(paid)的实际数据类型
    Ct = default(int)
}, "select (select sum(paid) from table_a) Paid, (select count(*) from table_b) ct")
.FirstOrDefaultAsync();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 20:15:38