在ASP.NET Core中如何调用PostgreSQL函数GetDriverStatusReport获取数据
ASP.NET Core 调用 PostgreSQL GetDriverStatusReport 函数的实现方法
你的函数返回refcursor游标类型,调用时必须在事务上下文中操作才能正常读取返回数据,以下是两种常用的可落地实现方案:
前置准备
- 安装对应依赖包:如果你的项目用EF Core开发,安装
Npgsql.EntityFrameworkCore.PostgreSQL;如果不用EF Core,直接安装Npgsql即可 - 定义接收返回数据的DTO类:
public class DriverStatusReportDto { // 字段类型可根据你实际表结构调整 public int DriverId { get; set; } public string DriverName { get; set; } [Column("Cash/Debit")] // 和函数返回的列名做映射 public string CashOrDebit { get; set; } public decimal Amount { get; set; } }
方案1:使用EF Core调用(推荐,适合已有EF Core上下文的项目)
- 先在
Program.cs中配置PostgreSQL数据库上下文
builder.Services.AddDbContext<你的自定义DbContext类名>(options => options.UseNpgsql("你的PostgreSQL数据库连接字符串"));
- 业务逻辑层调用代码:
public async Task<List<DriverStatusReportDto>> GetDriverReportsAsync() { var result = new List<DriverStatusReportDto>(); // 必须开启事务,refcursor依赖事务上下文才能读取 using var transaction = await _dbContext.Database.BeginTransactionAsync(); try { // 调用存储函数获取游标名称 var cursorName = await _dbContext.Database .SqlQuery<string>($"SELECT GetDriverStatusReport('report_cursor')") .FirstAsync(); // 从游标中拉取所有返回数据 result = await _dbContext.Database .SqlQuery<DriverStatusReportDto>($"FETCH ALL IN \"{cursorName}\"") .ToListAsync(); await transaction.CommitAsync(); } catch { await transaction.RollbackAsync(); throw; } return result; }
方案2:使用原生Npgsql调用(无需依赖EF Core)
直接操作数据库连接实现,适合没有用EF Core的轻量项目:
public async Task<List<DriverStatusReportDto>> GetDriverReportsAsync() { var result = new List<DriverStatusReportDto>(); var connString = "你的PostgreSQL数据库连接字符串"; await using var conn = new NpgsqlConnection(connString); await conn.OpenAsync(); // 开启事务 await using var transaction = await conn.BeginTransactionAsync(); try { // 调用函数获取游标 await using (var cmd = new NpgsqlCommand("SELECT GetDriverStatusReport('report_cursor')", conn, transaction)) { var cursorName = (string)await cmd.ExecuteScalarAsync(); // 读取游标返回的所有数据 await using var fetchCmd = new NpgsqlCommand($"FETCH ALL IN \"{cursorName}\"", conn, transaction); await using var reader = await fetchCmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) { result.Add(new DriverStatusReportDto { DriverId = reader.GetInt32(reader.GetOrdinal("Driver Id")), DriverName = reader.GetString(reader.GetOrdinal("Driver Name")), CashOrDebit = reader.GetString(reader.GetOrdinal("Cash/Debit")), Amount = reader.GetDecimal(reader.GetOrdinal("Amount")) }); } } await transaction.CommitAsync(); } catch { await transaction.RollbackAsync(); throw; } return result; }
常见问题排查
- 如果报字段不存在的错误,检查你代码里的列名和函数返回的列名是否完全一致,原函数返回的列名带空格,需要严格匹配
- 如果返回数据为空,先确认数据库连接字符串正确,对应业务表中存在符合条件的数据
内容的提问来源于stack exchange,提问作者M.N. Waleedh
相关产品推荐
相关产品推荐

