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

EF Core使用ExecuteSqlInterpolatedAsync调用存储过程无法获取返回列表

解决EF Core中调用存储过程返回-1而非结果集的问题

问题原因

ExecuteSqlInterpolatedAsync 是EF Core专门用于执行非查询SQL操作(如INSERT、UPDATE、DELETE)的方法,它的返回值是受影响的行数。对于包含SELECT语句的存储过程,该方法无法解析并返回结果集;当EF Core无法统计到明确的受影响行数时,就会返回-1,这就是你遇到的情况。

另外代码里的Task.Run(() => _dbContext.Database.ExecuteSqlInterpolatedAsync(...))完全多余,因为ExecuteSqlInterpolatedAsync本身就是异步方法,直接await即可,不需要额外开启线程。

解决方案

根据你的返回结果是否有对应实体类,分两种处理方式:

方式一:结果集对应已有实体类

如果存储过程返回的字段和你的DbContext中某个实体类的属性完全匹配,可以使用FromSqlInterpolated来获取结果:

  1. 确保你的实体类(比如ReportResult)结构与存储过程返回列匹配:
public class ReportResult
{
    // 属性名需与存储过程返回的列名一致
    public DateTime Date { get; set; }
    public string DataContent { get; set; }
    // 其他对应字段...
}
  1. 修改方法代码:
public async Task<List<ReportResult>> Report(string sStartDate, string sEndDate, string spName)
{
    try
    {
        var paramToDt = new SqlParameter("@TODATE", SqlDbType.VarChar) { Value = sStartDate };
        var paramFrmDt = new SqlParameter("@FROMDATE", SqlDbType.VarChar) { Value = sEndDate };

        // 直接调用FromSqlInterpolated获取结果集
        var results = await _dbContext.Set<ReportResult>()
            .FromSqlInterpolated($"EXEC {spName} @TODATE={paramToDt}, @FROMDATE={paramFrmDt}")
            .ToListAsync();

        return results;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

方式二:自定义返回DTO(无对应实体类)

如果存储过程返回的结果没有对应的实体类,可以先定义一个DTO类,再使用SqlQuery<T>(EF Core 6.0+支持)来获取结果:

  1. 定义匹配存储过程返回列的DTO:
public class ReportDto
{
    // 属性名需与存储过程返回的列名严格匹配(大小写取决于数据库配置)
    public int RecordId { get; set; }
    public decimal TotalAmount { get; set; }
    // 其他对应字段...
}
  1. 修改方法代码:
public async Task<List<ReportDto>> Report(string sStartDate, string sEndDate, string spName)
{
    try
    {
        var paramToDt = new SqlParameter("@TODATE", SqlDbType.VarChar) { Value = sStartDate };
        var paramFrmDt = new SqlParameter("@FROMDATE", SqlDbType.VarChar) { Value = sEndDate };

        // 使用SqlQuery执行存储过程并映射到DTO
        var results = await _dbContext.Database
            .SqlQuery<ReportDto>($"EXEC {spName} @TODATE=@p0, @FROMDATE=@p1", paramToDt, paramFrmDt)
            .ToListAsync();

        return results;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

额外注意事项

  • 确保存储过程的参数名与代码中定义的参数名完全一致,避免参数传递错误。
  • 如果存储过程返回多个结果集,需要调用NextResultAsync()来遍历后续结果集。
  • 移除多余的Task.Run()包裹,直接await异步方法即可,减少不必要的线程开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 03:17:10