【问题标题】:MSSQL Stored Procedure not reading parameter correctlyMSSQL 存储过程未正确读取参数
【发布时间】:2021-05-24 19:50:00
【问题描述】:

我正在使用 AWS RDS/Lambda/API Gateway 学习/构建 API。 DB 是 MSSQL,因为我们过去一直使用 SQL 数据库,而 Lambda 是在 Visual Studio 中用 C#(我也是 C# 的新手)编写的。

我已经用一个简单的虚拟用户表设置了一个测试数据库,并编写了一个基本的 SP 来获取数据。 SP 采用单个可选参数“用户”并返回找到该用户的所有列,如果没有发出参数,则返回所有列。

在 MSSMS 中进行了测试,SP 可以在有参数和没有参数的情况下工作。我已经在 Visual Studio 中编写了该函数,并使用 Mock Lambda 测试工具进行了测试。如果没有发送参数,那么我会得到一个完整的用户列表。但是,当我尝试传递参数时,阅读器执行但不返回任何结果。我已经检查并三次检查了参数名称和值,两者都应该是有效的。我不明白为什么会发生这种情况?我在 VB.net 中已经这样做了数千次,从来没有遇到过问题。

代码如下:

SP:

USE [playground]
GO
/****** Object:  StoredProcedure [dbo].[GetUsers]    Script Date: 22/02/2021 14:29:09 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[GetUsers]

    @User varchar(60) = null

AS

BEGIN

    SELECT * 
    FROM PlayUsers
    WHERE (@User IS NULL OR UName = @User)

END

C#代码:

public static class Function
    {
        /// <summary>
        /// Run a simple SP with optinal parameter to prove concept
        /// </summary>
        public static object FunctionHandler(ILambdaContext context)
        {
            var users = "";
            Console.WriteLine("*** Starting function ***");
            try
            {

                using (SqlConnection conn = new SqlConnection(GetConnectionString()))
                {
                    
                    SqlCommand cmd = new SqlCommand("GetUsers", conn)
                    {
                        CommandType = CommandType.StoredProcedure
                    };
                    cmd.Parameters.AddWithValue("@User", "BearDown");
                    //cmd.Parameters.Add("@User", SqlDbType.VarChar).Value = "BearDown";

                    conn.Open();

                    using (SqlDataReader rdr = cmd.ExecuteReader())
                    {
                        while (rdr.Read())
                        {
                            users += ToJson(rdr);
                        }
                    }

                    conn.Close();
                    cmd.Dispose();
                    conn.Dispose();
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine($"Exception thrown: {ex}");
            }
            finally
            {
                Console.WriteLine("*** End function  ***");
            }

            return users;
        }

        public static string ToJson(this SqlDataReader rdr)
        {
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);

            using (JsonWriter jsonWriter = new JsonTextWriter(sw))
            {
                jsonWriter.WriteStartArray();

                while (rdr.Read())
                {
                    jsonWriter.WriteStartObject();

                    int fields = rdr.FieldCount;

                    for (int i = 0; i < fields; i++)
                    {
                        jsonWriter.WritePropertyName(rdr.GetName(i));
                        jsonWriter.WriteValue(rdr[i]);
                    }

                    jsonWriter.WriteEndObject();
                }

                jsonWriter.WriteEndArray();

                return sw.ToString();
            }
        }
    }

如您所见,我已尝试使用 .Add 和 .AddWithValue 添加参数,但似乎都没有传递参数。我已经单步执行了代码,可以看到它在 SQL 阅读器中运行良好,没有遇到异常,但它从未找到任何结果。

在 rdr 中添加一个监视,它显示:“枚举未产生任何结果”,当使用参数时。但同样,在 MSSMS 中执行 SP 时,这两个值都可以正常工作。

** 更新 ** 在解决了这个问题后,我发现替换

using (SqlDataReader rdr = cmd.ExecuteReader())
                    {
                        while (rdr.Read())
                        {
                            users = rdr.ToJson();
                        }
                    }

只要

                    using (SqlDataReader rdr = cmd.ExecuteReader())
                    {
                      users = rdr.ToJson();
                    }

按要求工作。我想我会把它包装在 if (rdr.HasRows) 中,看起来像一个解决方案。

【问题讨论】:

  • 仅供参考,当您拥有using (SqlConnection conn ... 时,您无需致电conn.Close() 和/或conn.Dispose(),因为这是由using 处理的
  • @HansKesting 谢谢,我不确定。我 vb.net 时代的旧习惯
  • 您是否从数据库中获取每一行?仔细检查是否在 c# 中看到“BearDown”
  • 您的代码看起来正确,但您应该使用 Add 并传递正确的长度。使用StringBuilder 也有点奇怪,但对于其余的行不要挂在上面。当你说它通过阅读器时,它实际上是像接收行一样循环,还是跳过循环?
  • @TonyLaw:在 VB.NET 中使用using 也是正确的方法,因为它的价值。使用AddWithValue 作为参数通常是不受欢迎的。它通常有效,但偶尔会让您感到惊讶。以dbdelta.com/addwithvalue-is-evil为例

标签: c# sql amazon-web-services aws-lambda ado.net


【解决方案1】:

您在您的FunctionHandler 中调用rdr.Read()(“让读者进入下一条记录”),然后在您从那里调用的ToJson 函数中再次调用...我认为这不是预期的行为?您总是在那里跳过一条记录...我的建议是在FunctionHandler 中尝试不使用rer.Read()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-03
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多