【问题标题】:Call to SQL Server stored procedure failing in certain cases在某些情况下调用 SQL Server 存储过程失败
【发布时间】:2016-01-27 13:35:09
【问题描述】:

我很难理解为什么某个存储过程在我的一些数据库中停止工作,但在其他数据库中却没有。我希望有人可以帮助我解决这个问题。

简介

我继承了一个现有的 C# 应用程序,该应用程序连接到选择的 SQL Server 数据库,具体取决于提供给程序的区域性参数。示例:传递“en-CA”会导致程序连接到包含英语-加拿大内容的数据库。传递“fr-CA”会导致程序连接到带有法语-加拿大内容的数据库。这些数据库是从一个公共根数据库派生的。除了许多 NVARCHAR 字段的内容外,这些数据库基本相同。 (这种不同的数据库仅在开发过程中用于测试各种文化。

两个数据库都使用以下排序规则:SQL_Latin1_General_CP1_CI_AS

问题

我不确定这个问题是从什么时候开始的,但目前的情况是,如果我从 fr-CA 数据库中调用某个存储过程,那么它根本不会执行。 (我会更详细地解释这一点。)没有错误代码返回给程序。程序的行为就像没有找到记录一样。

但是,如果我从 en-CA 数据库中调用相同的存储过程,那么它会按预期运行,并且会向程序返回一条记录。

尝试过的步骤

如果我从 SSMS 运行存储过程,那么它会正确执行。

我已尝试将存储过程的定义从正确执行的数据库复制到未正确执行的数据库。这并没有解决问题。

我确实尝试使用 SQL Profiler 进行调试。当我对两个数据库运行存储过程时,我在跟踪中看到了一个条目。我没有看到列出的任何错误。在使用 Profiler 时,我承认我是新手。

当我说存储过程没有被执行时,我基于以下测试。我创建了一个包含几个字段的调试表:

create table DEBUG
(
    Id INTEGER,
    Line NVARCHAR(100)
);

在存储过程的顶部,在两个数据库中,我在第一行插入了以下语句:

INSERT INTO dbo.DEBUG VALUES (1, 'Top of Atms_Get_Tray_Infos');

当我的代码调用存储过程时,我希望在 DEBUG 表中看到一行。

如果我针对 en-CA 数据库运行程序,我确实看到了预期的行:

如果我清空 DEBUG 表,然后针对 fr-CA 数据库运行程序,则 DEBUG 表仍然为空。这个事实让我相信存储过程没有被执行。

数据库详情

这里是带有调试行的存储过程的定义:

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Atms_Get_Tray_Infos]
    @TrayNo AS NVARCHAR(10)
AS
BEGIN
    -- DEBUG
    INSERT INTO dbo.DEBUG VALUES (1, 'Top of Atms_Get_Tray_Infos');

    -- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
    SET NOCOUNT ON;

    BEGIN TRY
        SELECT  HTRAY.SEQ_HIST_PLATEAU AS TRAYNO,
                HTRAY.DATE_EXPIRATION_DATE AS EXPIRY,
                HTRAY.DATE_UTILISATION_DATE AS DATEUSED,
                HTRAY.LADATE_LAVAGE AS WASHDATE,
                HSTE.SEQ_CODE_QUAL_STERIL AS QLTYCODE,
                HSTE.NO_CHARGE AS CHGNO,
                HSTE.TEST_BIO_BON AS BIOTEST,
                FRML.CODE AS FORMULACODE,
                TRAY.NO_TYPE_PLATEAU AS TRAYCODE,
                TRAY.DESCRIPTION_S,
                TRAY.EstUrgent AS URGENT
        FROM dbo.HIST_PLAT HTRAY
        LEFT JOIN dbo.HIST_CHARG_STE HSTE ON HTRAY.LAST_SEQ_HIST_CHARGE_STERIL = HSTE.SEQ_HIST_CHARGE_STERIL
        INNER JOIN dbo.PLATEAUX TRAY ON TRAY.SEQ_PLATEAU = HTRAY.NO_SEQ_PLATEAU
        INNER JOIN dbo.FORMULE FRML ON HSTE.SEQ_FORMULE = FRML.SEQ_FORMULE
        WHERE HTRAY.SEQ_HIST_PLATEAU = @TrayNo
    END TRY

    BEGIN CATCH
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT  @ErrorMessage = ERROR_MESSAGE(),
                @ErrorSeverity = ERROR_SEVERITY(),
                @ErrorState = ERROR_STATE();
        RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
    END CATCH
END

感谢任何能帮助我解决此问题的帮助。谢谢!

【问题讨论】:

  • 如果您在 Profiler 的跟踪中看到一个条目,则过程 已执行。它可以在事务的范围内执行,稍后会回滚。这可以解释为什么您没有看到插入到 dbo.DEBUG 的行。
  • 你如何准确地调用程序?我的意思是,如果您的代码中有 sqlCmd.CommandName="[dbo].[Atms_Get_Tray_Infos]";sqlCmd.CommandName="[Atms_Get_Tray_Infos]"; 或其他任何内容(可能是动态 sql)。
  • @Vladimir,我没有看到任何可以在事务中调用存储过程的机制。另外,这是否可以解释为什么存储过程在某些数据库上按预期工作,而在其他数据库上却没有?
  • @RayGoudie,很难说具体的。正如您在回答中所说,您似乎确认您的 C# 代码存在问题。所以,你知道在哪里可以看得更远。

标签: c# sql-server database stored-procedures


【解决方案1】:

上面 Paolo 的评论让我调查了调用存储过程的实际 C# 代码。

在我看来,代码是为了复杂而复杂的。 有一种方法是处理对存储过程的所有调用的某个类。我用这个基本代码替换了那个代码:

DataSet dataSet = new DataSet("ReturnDs");
using (var connection = new System.Data.SqlClient.SqlConnection(theConnectStg))
{
    using (var command = new System.Data.SqlClient.SqlCommand(theStoreProcName, connection))
    {
        using (var dataAdapter = new System.Data.SqlClient.SqlDataAdapter(command))
        {
            command.CommandType = CommandType.StoredProcedure;
            if (theParameterList != null)
            {
                foreach (String str1 in theParameterList.ToArray())
                {
                    String parameterName = str1.Substring(0, str1.IndexOf(":"));
                    String str2 = str1.Substring(str1.IndexOf(":") + 1);
                    dataAdapter.SelectCommand.Parameters.Add(new SqlParameter(parameterName, SqlDbType.VarChar, 128));
                    dataAdapter.SelectCommand.Parameters[parameterName].Value = (object)str2;
                }
            }
            dataAdapter.Fill(dataSet);
        }
    }
}
return dataSet;

为了满足您的好奇心,theParameterList 参数是一个参数数组,每个参数的格式为“@variable:value”。我不是粉丝,但我现在坚持使用现有代码。

那么,为什么之前的代码对于某些数据库会失败?我还是不清楚。我很好奇,但我不想在这个问题上花更多时间。我的大脑很累。

谢谢你的线索,保罗!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多