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

.NET Core 6中Entity Framework Core调用表值函数(TVF)的问题

.NET Core 6 API调用带参表值函数(TVF)的解决方案

推荐方案:使用EF Core的FromSqlRaw/FromSqlInterpolated

.NET Core 6中EF Core已移除SqlQuery方法,官方推荐用FromSqlRaw(处理原生SQL字符串)或FromSqlInterpolated(安全传递参数、避免SQL注入)调用表值函数,无需手动管理数据库连接,能直接规避「连接当前状态为关闭」这类问题。

步骤1:定义匹配TVF返回结果的实体类

创建一个和TVF输出字段完全对应的实体类,假设你的TVF返回Id、ProductName、Price三个字段:

public class TvfProductResult
{
    public int Id { get; set; }
    public string ProductName { get; set; }
    public decimal Price { get; set; }
}

步骤2:在DbContext中注册无键实体

在你的DbContext中添加DbSet<TvfProductResult>,并配置为无键实体(因为TVF不是物理数据表):

public DbSet<TvfProductResult> TvfProductResults { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<TvfProductResult>().HasNoKey();
}

步骤3:在API控制器中实现GET调用

在GET方法中通过EF Core执行TVF调用,传入参数并返回JSON结果:

[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
    private readonly AppDbContext _dbContext;

    public ProductController(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpGet]
    public async Task<IActionResult> GetProductsByTvf(int categoryId, string keyword)
    {
        // 使用FromSqlInterpolated安全传递参数,自动处理SQL注入风险
        var results = await _dbContext.TvfProductResults
            .FromSqlInterpolated($"SELECT * FROM dbo.GetProductsByCategoryAndKeyword({categoryId}, {keyword})")
            .ToListAsync();

        return Ok(results);
    }
}

手动DbDataReader方案的连接问题修复(可选)

如果坚持使用DbDataReader方式,必须确保连接被正确打开并通过using块管理资源,示例代码如下:

[HttpGet]
public async Task<IActionResult> GetProductsByTvf(int categoryId, string keyword)
{
    using var connection = _dbContext.Database.GetDbConnection();
    await connection.OpenAsync(); // 必须手动打开数据库连接

    using var command = connection.CreateCommand();
    command.CommandText = "SELECT * FROM dbo.GetProductsByCategoryAndKeyword(@CategoryId, @Keyword)";
    command.Parameters.Add(new SqlParameter("@CategoryId", categoryId));
    command.Parameters.Add(new SqlParameter("@Keyword", keyword));

    using var reader = await command.ExecuteReaderAsync();
    var results = new List<TvfProductResult>();
    while (await reader.ReadAsync())
    {
        results.Add(new TvfProductResult
        {
            Id = reader.GetInt32(reader.GetOrdinal("Id")),
            ProductName = reader.GetString(reader.GetOrdinal("ProductName")),
            Price = reader.GetDecimal(reader.GetOrdinal("Price"))
        });
    }

    return Ok(results);
}

注意:这种方式需要手动处理参数映射、连接生命周期和数据读取逻辑,代码冗余度高,优先推荐使用第一种EF Core原生方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 02:10:57