【发布时间】:2022-01-10 00:59:51
【问题描述】:
场景
- 我正在使用 SQL Server 2017(无法更改)
- 我在 C# 控制台和 .NET Framework 4.5 中使用 Visual Studio 2019(可能会更改)
- 我使用 ADO.NET 是因为几年前我们还不能使用 Entity Framework,因为系统是用来处理返回至少 100k 行的存储过程(可能会更改)
情况
我有一个 USP,它返回一个至少 100k 行乘 20 个字段的表。我需要添加一个输出参数才能获得由 USP 本身创建的 ID。所以,情况是我需要返回一个表和一个 ID(称为ProcMonitorId)。我不知道这是否可能(请参阅解决方法部分)
到目前为止,SQL 级别似乎还不错:
CREATE PROCEDURE [myschema].[mystore]
@ProcMonitorId BIGINT OUTPUT
AS
BEGIN
BEGIN TRANSACTION
(...)
SELECT fields FROM myTable
SELECT @ProcMonitorId = @internalVariable
SQL 执行:
在存储库层(仅相关行,有人对示例的健康状况感到惊讶):
var command = new SqlCommand("myStoreProcedure", mycon);
command.CommandType = CommandType.StoredProcedure;
SqlParameter outPutParameter = new SqlParameter();
outPutParameter.ParameterName = "@ProcMonitorId";
outPutParameter.SqlDbType = System.Data.SqlDbType.BigInt;
outPutParameter.Direction = System.Data.ParameterDirection.Output;
command.Parameters.Add(outPutParameter);
// Open connection etc-etc that works
SqlDataAdapter da = new SqlDataAdapter(command);
DataTable dt = new DataTable();
string ProcMonitorId = outPutParameter.Value.ToString();
da.Fill(dt);
在添加 C# 级别的输出之前,一切正常。它在行中返回:
字符串 ProcMonitorId = outPutParameter.Value.ToString();
它返回NullReferenceException,因为Value 为空(不可能),当然,不能转换为字符串。我会通过添加? 来解决这种情况,但如果这种情况真的发生,我需要以任何方式将其作为错误捕获。主要思想是Value不能为null。
由于我没有任何 ORM 映射,(而且我的专长不是 ADO.NET 而是实体框架)我无法理解为什么为 null(不,在 SQL 层不为 null,总是返回一个值)
问题
如何解决此错误或如何返回 BIGINT 参数和表格结果?
解决方法
乍一看我必须快速解决它,我做了一个:
SELECT 1 as type, @procID as procid, null as data1, null as data2
UNION ALL
SELECT 2 as type, null as procid, data1, data2
为了在一个表上模拟“标题”和“数据”行。 但我不喜欢这个解决方案,也不是很优雅和灵活。我每次都要解析头部。
提前致谢,请评论任何内容、提示、帮助、解决方法,如果需要更多信息,我将很乐意更新我的答案。
我还可以将我的框架制作为 .NET Core 或更改为实体框架。我无法更改的是我的 SQL 版本
更新 #2
SQL 没有变化 - 仍然作为屏幕截图工作
在 C# 中 - 永远挂在外面
SqlConnection connection = new SqlConnection(ConfigurationManager.AppSettings["DbConnection"]);
connection.Open();
var command = new SqlCommand("myUSP", connection);
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = Convert.ToInt16(ConfigurationManager.AppSettings["DataBaseTimeOut"]);
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
SqlParameter r = command.Parameters.Add("@ProcMonitorId", SqlDbType.BigInt);
r.Direction = ParameterDirection.Output;
DataTable dt = new DataTable();
using (var rdr = command.ExecuteReader())
{
dt.Load(rdr);
long id = (long)r.Value;
}
SqlDataAdapter da = new SqlDataAdapter(command);
da.Fill(dt);
【问题讨论】:
-
不需要 DataAdapter 填充,因为表已经在 dt.Load 中加载(当然反之亦然)
-
@Steve 你是对的,我混淆了解决方案
-
您的程序有
BEGIN TRANSACTION,但没有COMMIT。理想情况下,您需要使用while (rdr.NextResult) { }来确保执行所有 SQL,但在这种情况下,请尝试将SELECT @ProcMonitorId放在首位 -
@Charlieface 提交包含在 (...)
标签: c# sql sql-server entity-framework ado.net