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

.NET5与EF Core5执行多表返回存储过程遇SqlQuery不存在报错如何解决

解决方案

错误原因

EF Core 5的Database门面原生没有提供SqlQuery<T>泛型方法,该API是EF6的遗留功能,EF Core默认不支持直接将原生SQL查询结果映射到未在DbContext中注册的DTO类型。

实现方案

方案1:注册无键实体(官方推荐)

无需引入额外依赖,符合EF Core的设计规范:

  1. 首先在你的MarketContext中注册DetailsClientsDto为无键实体,并添加对应的DbSet:
public class MarketContext : DbContext
{
    // 新增DbSet属性
    public DbSet<DetailsClientsDto> DetailsClients { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // 配置为无键实体,不会映射到实际数据表
        modelBuilder.Entity<DetailsClientsDto>().HasNoKey();
    }
}
  1. 修改查询代码,使用FromSqlRaw执行存储过程:
public async Task<DetailsClientsDto> GetDetailsRepository(SearchDetailsDto details)
{
    var sqlParameters = new[]
    {
        new SqlParameter
        {
            ParameterName = "@ID_USER",
            Value = details.IdUser,
            SqlDbType = SqlDbType.Int,
        },
        new SqlParameter
        {
            ParameterName = "@ID_CLIENT",
            // 修正原代码的拼写错误:detalles → details
            Value = details.IdClient,
            SqlDbType = SqlDbType.Int,
            IsNullable = true
        },
    };

    // 单结果用FirstOrDefaultAsync,多结果查询替换为ToListAsync即可
    return await _context.DetailsClients
        .FromSqlRaw("EXEC [dbo].[SPROC_DETAILS] @ID_USER, @ID_CLIENT", sqlParameters)
        .FirstOrDefaultAsync();
}

方案2:原生ADO.NET读取(无需修改DbContext)

如果不想修改DbContext的配置,可以直接从DbContext获取数据库连接,手动映射结果:

using Microsoft.Data.SqlClient; // 注意使用Microsoft.Data.SqlClient而非System.Data.SqlClient

public async Task<DetailsClientsDto> GetDetailsRepository(SearchDetailsDto details)
{
    var sqlParameters = new[]
    {
        new SqlParameter
        {
            ParameterName = "@ID_USER",
            Value = details.IdUser,
            SqlDbType = SqlDbType.Int,
        },
        new SqlParameter
        {
            ParameterName = "@ID_CLIENT",
            Value = details.IdClient,
            SqlDbType = SqlDbType.Int,
            IsNullable = true
        },
    };

    await using var connection = _context.Database.GetDbConnection();
    await connection.OpenAsync();

    await using var command = connection.CreateCommand();
    command.CommandText = "EXEC [dbo].[SPROC_DETAILS] @ID_USER, @ID_CLIENT";
    command.Parameters.AddRange(sqlParameters);

    await using var reader = await command.ExecuteReaderAsync();
    if (await reader.ReadAsync())
    {
        return new DetailsClientsDto
        {
            IdUser = reader.GetInt32(reader.GetOrdinal(nameof(DetailsClientsDto.IdUser))),
            IdClient = reader.GetInt32(reader.GetOrdinal(nameof(DetailsClientsDto.IdClient))),
            User = reader.IsDBNull(reader.GetOrdinal(nameof(DetailsClientsDto.User))) ? null : reader.GetString(reader.GetOrdinal(nameof(DetailsClientsDto.User))),
            Adress = reader.IsDBNull(reader.GetOrdinal(nameof(DetailsClientsDto.Adress))) ? null : reader.GetString(reader.GetOrdinal(nameof(DetailsClientsDto.Adress))),
            Car = reader.IsDBNull(reader.GetOrdinal(nameof(DetailsClientsDto.Car))) ? null : reader.GetString(reader.GetOrdinal(nameof(DetailsClientsDto.Car))),
            Color = reader.IsDBNull(reader.GetOrdinal(nameof(DetailsClientsDto.Color))) ? null : reader.GetString(reader.GetOrdinal(nameof(DetailsClientsDto.Color)))
        };
    }

    return null;
}

注意事项

  • 不要用Task.Run包裹EF Core的异步查询操作,EF Core提供的异步方法本身就是非阻塞的,额外包Task.Run只会浪费线程池资源
  • 执行存储过程的SQL语句需要完整列出所有输入参数,原代码中漏传了@ID_CLIENT参数
  • 确保存储过程返回的字段名和DetailsClientsDto的属性名完全一致,否则会出现映射失败的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 03:45:07