无法将 SQL 查询响应映射到 C# 变量

Unable to map SQL Query Response to C# variables

我有这个 SQL 查询脚本,我正试图通过 ADO.Net 代码调用它。

DECLARE   
  @Error NVARCHAR(MAX)
DECLARE
  @Errors TABLE
  (
    [Column_Name] VARCHAR(MAX),
    [Message] VARCHAR(MAX)
  )

IF NOT EXISTS(...)  
BEGIN  
  INSERT INTO @Errors
  SELECT
    'Col1',
    'value does not exist.'
END

IF NOT EXISTS(...)  
BEGIN  
  INSERT INTO @Errors
  SELECT
    'Col2',
    'value does not exist.'
END

IF EXISTS (SELECT * FROM @Errors)
BEGIN 
  SET @Error = (  
    SELECT  
      [Column_Name],
      [Message]
    FROM
      @Errors
    FOR JSON PATH, INCLUDE_NULL_VALUES
  );

  SELECT @Error AS 'Error_Message'
END
ELSE
BEGIN
    SELECT TOP(1) Id
    FROM dbo.table
END

这是 C# 代码

using (var conn = await _connectionFactory.OpenConnectionAsync(database: "dbName", readOnly: true))
{
    using (var cmd = conn.CreateCommandFromSqlFile(path, "test.sql"))
    {
        string errors = string.Empty;
        Guid id;

        using (DataReader reader = await cmd.ExecuteReaderAsync(ct))
        {
            if (reader.HasRows)
            {
                while (await reader.ReadAsync(ct))
                {
                    errors = reader.GetString("Error_Message");
                    id = reader.GetGuid("Id");
                }
            }
        }
    }
}

SQL 脚本总是 returns、Error_MessageId,具体取决于条件。如果 @Errors table 被填充,它 returns Error_Message 如果没有错误那么它 returns Id.

我试图在 C# 代码中获取这些值,但它在 while 块中抛出异常,因为其中一个值 Error_MessageId 不会出席。

我需要帮助才能将这些值优雅地添加到我的 C# 代码中。有办法吗?

您可以使用SqlDataReader

GetName功能
using (SqlDataReader reader = await cmd.ExecuteReaderAsync(ct))
{
    if (reader.HasRows)
    {
        while (await reader.ReadAsync(ct))
        {
            var colName = reader.GetName(0);
            if (colName.Equals("Error_Message")
                errors = reader.GetString("Error_Message");
            else 
                id = reader.GetGuid("Id");
        }
    }
}

https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqldatareader.getname?view=dotnet-plat-ext-3.1#System_Data_SqlClient_SqlDataReader_GetName_System_Int32_

我认为没有一种“优雅”的方式可以按照您构建它的方式来做,恕我直言

  • 您可以使用 c# try catch 来捕获不存在错误时发生的异常,但异常处理很慢,不应用作正常的控制流程
  • 您可以更改您的查询,使它们 return 具有相同的列名,这样就不会再有任何例外,并且 id 表示为一个字符串,并且您可以使用另一列来指导您字符串是 GUId 还是错误,以便您可以适当地解析或报告它,或者您尝试解析它并查看它是否有效
  • 您可以更改查询,使它们始终有两列 - 一个字符串和一个 GUId,其中一列始终为 null,并使用 null 来确定您拥有哪种类型的东西
  • 您总是可以 select 您的错误和 ID,并利用 sql 服务器允许您打开多个结果集的事实

但实际上我认为我会停止尝试将 return SQL 错误作为结果集而只是 throw them as exceptions,并在 c# 中捕获它们。采用以空白开头的字符串的模式,检查 col1,如果不存在,则将“col1 不存在”附加到字符串,检查 col2 并可能附加“col2 不存在”.. 然后如果字符串不为空 THROW it,否则 return 您的结果集。 C# 会遇到异常并显示有用的错误消息(如果您想以不同的方式处理它,而不是仅仅向用户报告,您可以提供可变代码)