Entity Framework Core无法捕获存储过程SQL catch块抛出的异常
问题原因
当存储过程在TRY/CATCH块的CATCH部分抛出错误时,SQL Server的消息发送逻辑导致EF Core无法捕获错误:
TRY块中的报错触发CATCH后,没有结果集被生成返回- SQL Server会先向客户端发送「结果集结束」的信号,之后才传递错误信息
- EF Core的
FromSqlInterpolated配合ToList()在收到「结果集结束」信号后,就终止了数据读取流程,不会再处理后续的错误消息
而移除TRY/CATCH直接抛出错误时,SQL Server会立即发送错误信息,EF Core能正常捕获。
解决方案
由于你需要保留TRY/CATCH执行额外操作,可采用以下两种方案:
方案1:改用ExecuteSqlInterpolated执行存储过程
如果存储过程无需返回实体结果集,用ExecuteSqlInterpolated替代FromSqlInterpolated,它会完整读取SQL Server返回的所有消息,包括后续的错误:
using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using SQLExceptionTest.Models; var builder = new DbContextOptionsBuilder<TESTNU40Context>(); builder.UseSqlServer("Data Source=MyServer; Initial Catalog=MyDB; Integrated Security=True; TrustServerCertificate=True"); var context = new TESTNU40Context(builder.Options); try { var affectedRows = context.Database.ExecuteSqlInterpolated($"SqlExceptionTest"); Console.WriteLine($"Affected rows: {affectedRows}"); } catch (Exception e) { Console.WriteLine(e.ToString()); } Console.ReadLine();
方案2:在CATCH块中先返回错误标记结果集
修改存储过程,在抛出错误前先返回一个包含错误标识的结果集,这样EF Core在读取结果集后会继续处理后续的错误:
create procedure SqlExceptionTest as set nocount on; begin try select 1/0 as test; end try begin catch -- 返回错误标记结果集 SELECT 'Error' AS ResultType, ERROR_MESSAGE() AS ErrorMessage; -- 抛出错误 throw 51000, 'throw in catch', 1; end catch
对应的代码可以先检查结果集的错误标识,同时EF Core会捕获后续抛出的错误:
using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using SQLExceptionTest.Models; var builder = new DbContextOptionsBuilder<TESTNU40Context>(); builder.UseSqlServer("Data Source=MyServer; Initial Catalog=MyDB; Integrated Security=True; TrustServerCertificate=True"); var context = new TESTNU40Context(builder.Options); try { var r = context.SQLExceptionTestResults.FromSqlInterpolated($"SqlExceptionTest").ToList(); // 检查结果集中的错误标记 if(r.Any(item => item.ResultType == "Error")) { Console.WriteLine($"Business error: {r.First().ErrorMessage}"); } Console.WriteLine($"Result count: { r.Count}"); } catch (Exception e) { Console.WriteLine(e.ToString()); } Console.ReadLine();
补充提示
- 确保使用较新版本的EF Core和Microsoft.Data.SqlClient,旧版本可能存在类似的消息处理缺陷
- 若无需返回实体结果,方案1更简洁;若需同时返回结果和处理错误,方案2更适配业务场景
内容的提问来源于stack exchange,提问作者bowend01
相关产品推荐
相关产品推荐

