ASP.NET Core 3.1执行存储过程并将多结果集赋值给变量
解决ASP.NET Core 3.1中捕获存储过程多结果集的问题
要捕获存储过程返回的多个结果集,你需要使用ADO.NET原生的SqlDataReader来处理,因为EF Core 3.1的ExecuteSqlRaw/FromSqlRaw仅支持单结果集读取。以下是具体实现步骤:
1. 定义对应结果集的实体类
根据存储过程返回的三个结果集的字段,分别创建实体类(示例需根据实际字段调整):
// 第一个结果集的实体(对应CaseId、EpisodeId等字段) public class CandidateInfo { public int CaseId { get; set; } public int EpisodeId { get; set; } // 添加其他对应字段,如PatientName、DiagnosisDate等 } // 第二个结果集的实体 public class SummaryStats { public int TotalCandidates { get; set; } public decimal AverageScore { get; set; } // 添加其他对应字段 } // 第三个结果集的实体 public class EligibilityRules { public string RuleName { get; set; } public bool IsActive { get; set; } // 添加其他对应字段 }
2. 更新ViewModel结构
让你的ViewModel包含三个结果集的集合属性:
public class SpPotentialCandidatesForOncotypeDXViewModel { public List<CandidateInfo> Candidates { get; set; } public List<SummaryStats> SummaryData { get; set; } public List<EligibilityRules> RuleData { get; set; } }
3. 修改数据获取方法
通过DbContext获取数据库连接,使用SqlCommand和SqlDataReader依次读取三个结果集:
public SpPotentialCandidatesForOncotypeDXViewModel GetPotentialCandidatesForTheOncotypeDXData(DateTime startDate, DateTime endDate) { var viewModel = new SpPotentialCandidatesForOncotypeDXViewModel(); var dbConnection = _dbContext.Database.GetDbConnection(); try { dbConnection.Open(); // 创建存储过程命令 using var command = dbConnection.CreateCommand(); command.CommandText = "spPotentialCandidatesForOncotypeDX"; command.CommandType = System.Data.CommandType.StoredProcedure; // 添加存储过程参数(参数名需与存储过程定义一致) var startParam = command.CreateParameter(); startParam.ParameterName = "@startDate"; startParam.Value = startDate; command.Parameters.Add(startParam); var endParam = command.CreateParameter(); endParam.ParameterName = "@endDate"; endParam.Value = endDate; command.Parameters.Add(endParam); // 执行命令获取数据阅读器 using var reader = command.ExecuteReader(); // 读取第一个结果集 viewModel.Candidates = new List<CandidateInfo>(); while (reader.Read()) { var candidate = new CandidateInfo { CaseId = reader.GetInt32(reader.GetOrdinal("CaseId")), EpisodeId = reader.GetInt32(reader.GetOrdinal("EpisodeId")), // 处理可能为null的字段:先判断是否为DBNull再赋值 // PatientName = reader.IsDBNull(reader.GetOrdinal("PatientName")) ? null : reader.GetString(reader.GetOrdinal("PatientName")) }; viewModel.Candidates.Add(candidate); } // 切换到第二个结果集 reader.NextResult(); viewModel.SummaryData = new List<SummaryStats>(); while (reader.Read()) { var stats = new SummaryStats { TotalCandidates = reader.GetInt32(reader.GetOrdinal("TotalCandidates")), AverageScore = reader.GetDecimal(reader.GetOrdinal("AverageScore")) }; viewModel.SummaryData.Add(stats); } // 切换到第三个结果集 reader.NextResult(); viewModel.RuleData = new List<EligibilityRules>(); while (reader.Read()) { var rule = new EligibilityRules { RuleName = reader.GetString(reader.GetOrdinal("RuleName")), IsActive = reader.GetBoolean(reader.GetOrdinal("IsActive")) }; viewModel.RuleData.Add(rule); } } catch (Exception ex) { AppLog.WriteError("GetPotentialCandidatesForTheOncotypeDXData", ex.Message); } finally { // 确保连接关闭 if (dbConnection.State == System.Data.ConnectionState.Open) { dbConnection.Close(); } } return viewModel; }
4. 在视图中使用结果集
通过ViewModel遍历各个结果集输出:
@model SpPotentialCandidatesForOncotypeDXViewModel <h2>候选患者列表</h2> <table class="table"> <thead> <tr> <th>Case ID</th> <th>Episode ID</th> </tr> </thead> <tbody> @foreach (var candidate in Model.Candidates) { <tr> <td>@candidate.CaseId</td> <td>@candidate.EpisodeId</td> </tr> } </tbody> </table> <h2>统计数据</h2> @foreach (var stats in Model.SummaryData) { <p>总候选人数:@stats.TotalCandidates,平均评分:@stats.AverageScore</p> } <h2> eligibility规则</h2> <ul> @foreach (var rule in Model.RuleData) { <li>@rule.RuleName:@(rule.IsActive ? "启用" : "禁用")</li> } </ul>
关键注意事项
- 参数名必须与存储过程中定义的参数名完全一致,避免使用
@p0这类占位符,防止参数匹配错误。 - 读取字段时,使用
GetOrdinal获取列索引比直接用列名更安全,可避免大小写或列名顺序变化导致的错误。 - 处理可空字段时,需先通过
reader.IsDBNull()判断,再进行赋值,避免抛出空值异常。
内容的提问来源于stack exchange,提问作者Fokwa Best
相关产品推荐
相关产品推荐

