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

EF Core执行存储过程返回-1,如何转Linq或获取正确结果?

问题解决:EF Core调用存储过程返回-1,及等价Linq实现

一、正确调用存储过程获取结果

你用ExecuteSqlRawAsync返回-1是因为这个方法的作用是返回SQL语句影响的行数,而你的存储过程是执行查询返回结果集,所以得用FromSqlRawAsync来获取查询结果。同时要使用参数化查询,避免SQL注入风险。

实现步骤:

  1. 先创建一个类用来接收存储过程的返回结果:
public class TotalRecordsResult
{
    public int TotalRecords { get; set; }
}
  1. 调用存储过程的正确代码:
// 定义参数,避免SQL注入
var userIdParam = new SqlParameter("@UserId", userId);
var startDateParam = new SqlParameter("@StartDate", request.StartDate);
var endDateParam = new SqlParameter("@EndDate", request.EndDate);

// 执行存储过程并获取结果
var result = await _context.Set<TotalRecordsResult>()
    .FromSqlRaw("EXEC LeadScoring_CountClosedActions @UserId, @StartDate, @EndDate", userIdParam, startDateParam, endDateParam)
    .FirstOrDefaultAsync();

var count = result?.TotalRecords ?? 0;

这样就能正确拿到存储过程返回的统计值,而不是-1。

二、等价Linq实现(匹配原存储过程逻辑)

先拆解原存储过程的核心逻辑:

  1. 关联LeadScoringActions和LeadScoringLeads表
  2. 按条件过滤记录(指定用户、日期范围、排除系统关闭类型、Lead.Extra不为空)
  3. 统计满足条件的记录中,不重复的Lead.Extra的数量(原存储过程用GROUP BY+窗口函数的写法,本质就是统计去重后的Lead.Extra个数)

简洁高效的Linq写法:

var count = await _context.Actions
    .Where(a => 
        a.AssignedToUserId == userId &&
        a.ActionResultType != LeadScoringConstants.SystemClosed &&
        a.DateCompleted > DateTime.Today.AddDays(request.StartDate) &&
        a.DateCompleted <= DateTime.Today.AddDays(request.EndDate) &&
        a.Lead.Extra != null)
    // 提取符合条件的Lead.Extra,去重后统计数量
    .Select(a => a.Lead.Extra)
    .Distinct()
    .CountAsync();

如果要严格对应原存储过程的GROUP BY+窗口函数逻辑(虽然没必要,因为和上面写法等价),也可以这么写:

var groupedResult = await _context.Actions
    .Include(a => a.Lead)
    .Where(a => 
        a.AssignedToUserId == userId &&
        a.ActionResultType != LeadScoringConstants.SystemClosed &&
        a.DateCompleted > DateTime.Today.AddDays(request.StartDate) &&
        a.DateCompleted <= DateTime.Today.AddDays(request.EndDate) &&
        a.Lead.Extra != null)
    .GroupBy(a => a.Lead.Extra)
    .Select(g => new { TotalGroups = _context.Actions
        .Where(a2 => 
            a2.AssignedToUserId == userId &&
            a2.ActionResultType != LeadScoringConstants.SystemClosed &&
            a2.DateCompleted > DateTime.Today.AddDays(request.StartDate) &&
            a2.DateCompleted <= DateTime.Today.AddDays(request.EndDate) &&
            a2.Lead.Extra != null)
        .Select(a2 => a2.Lead.Extra)
        .Distinct()
        .Count() })
    .FirstOrDefaultAsync();

var count = groupedResult?.TotalGroups ?? 0;

三、存储过程 vs Linq 的选择建议

  • 若业务逻辑复杂、需要利用SQL特定优化(比如复杂索引、自定义函数),或者需要统一维护SQL逻辑,选存储过程更合适。
  • 若追求代码可读性、强类型检查,且逻辑不复杂,Linq更优——它能自动处理实体映射,避免手动创建结果类,EF Core也会生成优化后的SQL。
  • 无论选哪种方式,绝对不要用字符串拼接参数,必须用参数化查询防止SQL注入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 02:46:17