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

ASP.NET Core Web API中EF Core Power Tools生成存储过程代码异常问题

问题场景

使用环境:

  • VS2022、C#
  • EF Core 7、ASP.NET Core Web API
  • SQL Server 2019

按EF Core Power Tools官方文档完成逆向工程后,实体类和DbContext生成正常,但处理存储过程usp_tblParts_Select时遇到两个问题:

  1. 生成存储过程对应的usp_tblParts_SelectResult类后,尝试自动生成控制器时提示「未找到主键」。
  2. 修改OnModelCreatingGeneratedProcedures中的配置,将HasNoKey改为HasKey(e => e.PartId)后,控制器生成成功,但调用GET /api/usp_tblParts_SelectResult/{id}触发SqlClient异常,提示「无效的对象名'usp_tblParts_SelectResult'」——程序误将类名当作数据库表名传递,而非调用目标存储过程。

解决方案

1. 明确无键实体的映射逻辑

EF Core Power Tools生成的存储过程返回类默认用HasNoKey()配置(因为存储过程结果集本身无数据库主键约束),直接修改为HasKey()会让EF Core将该类识别为普通实体表,导致调用时访问不存在的表对象。正确的做法是保留HasNoKey()配置,手动处理控制器的主键需求。

2. 手动编写存储过程调用的API控制器

不要依赖自动生成器直接基于usp_tblParts_SelectResult类创建控制器,而是手动编写控制器代码,显式调用存储过程:

[ApiController]
[Route("api/[controller]")]
public class PartsController : ControllerBase
{
    private readonly YourDbContext _context;

    public PartsController(YourDbContext context)
    {
        _context = context;
    }

    // GET: api/Parts/{id}
    [HttpGet("{id}")]
    public async Task<ActionResult<usp_tblParts_SelectResult>> GetPart(int id)
    {
        var result = await _context.usp_tblParts_SelectResult
            .FromSqlRaw("EXEC usp_tblParts_Select @PartId = {0}", id)
            .FirstOrDefaultAsync();

        if (result == null)
        {
            return NotFound();
        }

        return result;
    }

    // 批量查询接口
    [HttpGet]
    public async Task<ActionResult<IEnumerable<usp_tblParts_SelectResult>>> GetAllParts()
    {
        return await _context.usp_tblParts_SelectResult
            .FromSqlRaw("EXEC usp_tblParts_Select")
            .ToListAsync();
    }
}

3. 封装存储过程调用(可选优化)

为了避免控制器中直接编写SQL,可以在DbContext中添加专门的方法封装存储过程调用:

public partial class YourDbContext : DbContext
{
    // 已有的DbSet和配置...

    public async Task<usp_tblParts_SelectResult> GetPartByIdAsync(int partId)
    {
        var parameter = new SqlParameter("@PartId", partId);
        return await this.usp_tblParts_SelectResult
            .FromSqlRaw("EXEC usp_tblParts_Select @PartId", parameter)
            .FirstOrDefaultAsync();
    }

    public async Task<List<usp_tblParts_SelectResult>> GetAllPartsAsync()
    {
        return await this.usp_tblParts_SelectResult
            .FromSqlRaw("EXEC usp_tblParts_Select")
            .ToListAsync();
    }
}

之后控制器只需调用封装方法即可:

[HttpGet("{id}")]
public async Task<ActionResult<usp_tblParts_SelectResult>> GetPart(int id)
{
    var result = await _context.GetPartByIdAsync(id);
    if (result == null)
    {
        return NotFound();
    }
    return result;
}

关键说明

  • 存储过程的返回类属于无键实体,EF Core不会将其映射到数据库表,必须通过FromSqlRaw或FromSqlInterpolated显式触发存储过程调用。
  • 自动控制器生成器仅适配有主键映射的实体表,存储过程返回类不适合用自动生成器,手动编写控制器更灵活可控。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 19:27:20