Почему мой пакет служб SSIS дает сбой при первом запуске, но не при втором?«Объект не может быть приведен из DBNULL к другим типам» - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть проблема, которая вызывает сбой моего пакета служб SSIS при его первом выполнении, в то время как при втором последующем выполнении проблема автоматически решается, и пакет служб SSIS выполняется успешно.

Проект: миграция пакета

  • SQL Server 2008 R2 для SQL Server, SSDT 2016
  • Visual Studio 2008 для Visual Studio 2015

Дело:

Один из моихперенесены пакеты служб SSIS, в которых есть задача сценария:

  • Выполнить хранимую процедуру с одним параметром OUTPUT, чтобы получить количество строк
  • Записать возвращенные строки в текстовый файл в формате CSV.

Хранимая процедура выполняется по заданию этого скрипта;возвращает (тысячи, миллионы строк) вместе с одним параметром OUTPUT, который содержит число строк, возвращаемое хранимой процедурой.

Проблема:

Этот пакет служб SSIS случайно завершается при первом выполнении с ошибкой -

"Объект не может быть приведен из DBNULL к другим типам"

и при его втором выполнении выполняется успешно.

Когда мы погуглили эту ошибку,Наиболее распространенное найденное решение - сначала проверить значение переменной: является ли оно значением INT и имеет ли какое-либо значение, а затем только преобразует.

Однако это решение здесь не применяется, как при выполнении пакета служб SSIS.во второй раз он успешно выполняется.

Еще одна вещь, на которую следует обратить внимание, это то, что при случайном сбое пакета SSIS он записывает CSV-файл с неполной строкой, и при втором выполнении эта проблема также решается.

Похоже, что вышеуказанная ошибка не является действительной ошибкой и по неизвестным причинам не дает действительной ошибки.

Является ли это dЕсли какая-либо конфигурация отсутствует на уровне служб SSIS / SQL или есть какие-либо другие проблемы?

Ниже приведен код SCRIPT и хранимой процедуры.

Каждый случайный сбой обнаруживается в нижней строке кода SCRIPT. Однако при втором запуске такой проблемы не возникло.Так что, похоже, это не проблема конверсии, а скорее проблема конфигурации 2016 года или какой-то другой способ кодирования -

  listRowCounts.Add(Convert.ToInt32(outputparm.Value));

Ниже вы найдете:

  1. часть кода задачи скрипта, в которой появляется ошибка &

  2. Часть кода хранимой процедуры, по которой мы получаем число строк и устанавливаем его в переменной OUTPUT

В задаче «Сценарий» под кодом существует несколько точек входа, созданных, чтобы знать, до какой точки выполняется код :-

// Write to sysout
Console.WriteLine("Test<NUMBER>");

--||--**-- --||--**-- --||--**-- --||--**-- --||--**-- 
 SCRIPT code part for WriteData only--

        public void WriteData(string strExamRegionCode, string strdivisionCode, string strResultFileName, DateTime dtmStdDate)
         {
             SqlConnection conn = new SqlConnection(strConnectionStringLog);
             SqlCommand cmd = null;
             SqlDataReader rdr = null;

            try
             {
                 //Open the connection 
                 conn.Open();

                // Create the command 
                 cmd = new SqlCommand("usp_Exam_ResultManifest_ProcList_Get", conn);
                 cmd.CommandType = CommandType.StoredProcedure;
                 cmd.Parameters.Add(new SqlParameter("@Exam_region_code", strExamRegionCode));
                 cmd.Parameters.Add(new SqlParameter("@Exam_division_code", strdivisionCode));
                 cmd.Parameters.Add(new SqlParameter("@Result_file_name", strResultFileName));
                 // Return the resultset 
                 rdr = cmd.ExecuteReader();


                 // Write to sysout
                 Console.WriteLine("Test12");

                // Fail if no rows returned
                 if (!rdr.HasRows)
                 {
                     // Log error to database 
                     string strCustomMessage = "No data returned by calling stored procedure usp_Exam_ResultManifest_ProcList_Get with parameters: " + strExamRegionCode + ", " + strdivisionCode + ", " + strResultFileName + ", " + dtmStdDate.ToString("yyyyMMdd");
                     LogCustomMessage(strConnectionStringLog, "OnError", strMachineName, strUserName, strPackageName, strPackageID, strExecutiondivisionGUID, strContainerStartTime, 100, strCustomMessage);

                    // Write to sysout
                     Console.WriteLine(strCustomMessage);

                    // Fail the package - error will be written to table sysssislog 
                     throw new MyAppException(strCustomMessage);

                }
                 else
                 {
                     // Call the Result Get stored procedure(s) to retrieve the Result data

                    while (rdr.Read())
                     {
                         // Get the stored procedure name
                         string strResultGetStoredProcedureName = rdr["Result_get_storedprocedure_name"].ToString();

                        // Write to sysout
                         Console.WriteLine("Test13");

                        try
                         {
                             SqlConnection connFDA = new SqlConnection(strConnectionStringResult);
                             SqlCommand cmdFDA = null;
                             SqlDataReader rdrFDA = null;

                            //Open the connection 
                             connFDA.Open();

                            // Run the sproc to return the Result data
                             cmdFDA = new SqlCommand(strResultGetStoredProcedureName, connFDA);
                             cmdFDA.CommandType = CommandType.Text;

                            SqlParameter parm1 = new SqlParameter("@Std_date", SqlDbType.DateTime);
                             parm1.Value = dtmStdDate;
                             parm1.Direction = ParameterDirection.Input;
                             cmdFDA.Parameters.Add(parm1);

                            SqlParameter parm2 = new SqlParameter("@Exam_Source_Section_division", SqlDbType.VarChar);
                             parm2.Value = strdivisionCode;
                             parm2.Direction = ParameterDirection.Input;
                             cmdFDA.Parameters.Add(parm2);

                            SqlParameter outputparm = new SqlParameter("@rows_returned", SqlDbType.Int);
                             outputparm.Direction = ParameterDirection.Output;
                             outputparm.Size = int.MaxValue;
                             cmdFDA.Parameters.Add(outputparm);

                            // Write to sysout
                             Console.WriteLine("Test14");

                            if (Dts.Variables["strForceRecompileObjects"].Value.ToString().Contains(strResultGetStoredProcedureName))
                             {

                                cmdFDA.CommandText = cmdFDA.CommandText + " @Std_date, @Exam_Source_Section_division, @rows_returned OUT WITH RECOMPILE;";

                                // Write to sysout
                                 Console.WriteLine("Test15");

                            }
                             else
                             {
                                 cmdFDA.CommandText = cmdFDA.CommandText + " @Std_date, @Exam_Source_Section_division, @rows_returned OUT;";

                                // Write to sysout
                                 Console.WriteLine("Test16");

                            }

                            // Result file generation timeout issue
                             cmdFDA.CommandTimeout = 1600;

                            // Write to sysout
                             Console.WriteLine("B4_cmdFDA_Execution");

                            // Return the resultset 
                             rdrFDA = cmdFDA.ExecuteReader();

                            // Write to sysout
                             Console.WriteLine("AFTER_cmdFDA_Execution");

                            if (rdrFDA.HasRows)
                             {
                                 // Write to sysout
                                 Console.WriteLine("rdrFDA has rows.");
                             }
                             else
                             {
                                 // Write to sysout
                                 Console.WriteLine("rdrFDA has NO rows.");

                            }


                            // Write to sysout
                             Console.WriteLine("TT");

                            // Write to sysout
                             Console.WriteLine("Test17");

                            try
                             {
                                 // Loop through the Result data and write to the file
                                 while (rdrFDA.Read())
                                 {

                                    // Write the row data to the file
                                     string strRowData = rdrFDA["row_data"].ToString();

                                    // Write to sysout
                                     //Console.WriteLine("Test18");

                                    int intControlId = Convert.ToInt32(rdrFDA["Result_control_id"]);
                                     if (!listControlIds.Contains(intControlId))
                                     {
                                         listControlIds.Add(intControlId);
                                         // Write to sysout
                                         Console.WriteLine("Test19");
                                     }

                                    WriteFile(strRowData);
                                     // Write to sysout
                                     //Console.WriteLine("Test20");

                                }

                            }
                             catch (Exception ex)
                             {
                                 // Log error to database 
                                 string strCustomMessage = "Error rdrFDA.Read  - stored procedure " + strResultGetStoredProcedureName + " with parameters: " + dtmStdDate.ToString("yyyyMMdd") + ", " + strdivisionCode + ", Error: " + ex.Message;
                                 LogCustomMessage(strConnectionStringLog, "OnError", strMachineName, strUserName, strPackageName, strPackageID, strExecutiondivisionGUID, strContainerStartTime, 100, strCustomMessage);

                                // Write to sysout
                                 Console.WriteLine(strCustomMessage);

                                // Fail the package - error will be written to table sysssislog 
                                 throw;
                             }

                            // Close the reader
                             rdrFDA.Close();

                            // Write to sysout
                             Console.WriteLine("Test21");


                             // Write to sysout
                             Console.WriteLine("abc");
                             Console.WriteLine("xyz" + Convert.ToString(outputparm.Value));
                             Console.WriteLine("def");

                            // Keep track of row counts - for the trailer row (MUST be after closing the reader)
                             listRowCounts.Add(Convert.ToInt32(outputparm.Value));

                            // Write to sysout
                             Console.WriteLine("Test22");

                            // Close the connection
                             connFDA.Close();
                         }
                         catch (Exception ex)
                         {
                             // Log error to database 
                             string strCustomMessage = "Error retrieving data for writing to the output file  - stored procedure " + strResultGetStoredProcedureName + " with parameters: " + dtmStdDate.ToString("yyyyMMdd") + ", " + strdivisionCode + ", Error: " + ex.Message;
                             LogCustomMessage(strConnectionStringLog, "OnError", strMachineName, strUserName, strPackageName, strPackageID, strExecutiondivisionGUID, strContainerStartTime, 100, strCustomMessage);

                            // Write to sysout
                             Console.WriteLine(strCustomMessage);

                            // Fail the package - error will be written to table sysssislog 
                             throw;
                         }
                     }

                    rdr.Close();
                     conn.Close();

                }
             }
             catch (Exception ex)
             {
                 // Log error to database 
                 string strCustomMessage = "Error retrieving data for writing to the output file with parameters: " + strExamRegionCode + ", " + strdivisionCode + ", " + strResultFileName + ", " + dtmStdDate.ToString("yyyyMMdd") + ", Error: " + ex.Message;
                 LogCustomMessage(strConnectionStringLog, "OnError", strMachineName, strUserName, strPackageName, strPackageID, strExecutiondivisionGUID, strContainerStartTime, 100, strCustomMessage);

                // Write to sysout
                 Console.WriteLine(strCustomMessage);

                // Fail the package - error will be written to table sysssislog 
                 throw;
             }
         }


 --||--**-- --||--**-- --||--**-- --||--**-- --||--**-- 


 --||--**-- --||--**-- --||--**-- --||--**-- --||--**-- 
 ---Stored proedure code where setting OUTPUT parameter value ONLY: - 

CREATE PROCEDURE [dbo].[p_result_get_SchoolItems_exam_v18]       
    @std_date DATETIME = NULL,
    @exam_Source_Section_division VARCHAR(10) = NULL,
    @rows_returned INT OUTPUT,
    @debug TINYINT = 0
WITH EXECUTE AS CALLER
AS
    SET NOCOUNT ON

    /*
     ** Declare and set error tracking and debugging variables
     */

    DECLARE @ProcName            sysname,
            @Error               int,
            @Raiserror           int,
            @CustomErrorSeverity int ,
            @CustomErrorState    int,
            @ErrorSeverity       int ,
            @ErrorState          int,
            @Msg                 varchar(255),
            @Rowcount            int, 
            @RowCnt              int;

     SET @ProcName = object_name(@@procid);
     SET @Error = 0;
     SET @Raiserror = 0;
     SET @Msg = '';
     SET @Rowcount = 0;
     SET @RowCnt = 0;
     SET @CustomErrorSeverity = 11;
     SET @CustomErrorState = 1;

    /*
     ** Declare variables used to implement procedure specific functionality
     */
     DECLARE @default_date datetime;
     DECLARE @working_date datetime;
     DECLARE @exam_region_code varchar(10);  
     DECLARE @SchoolID varchar(8);
     DECLARE @result_control_id int;
     SELECT @default_date = '29991231';


     BEGIN TRY

        IF (@debug>=1) PRINT @ProcName + ' : ' + convert(varchar(30),getdate(),109) + ': Entering procedure ...';

            --To avoid NULL/DBNULL issues coming in SSIS Package execution due to below direct SET via @@ROWCOUNT; added same Query as above but with COUNT(1) only. 
             --SET @rows_returned = @@ROWCOUNT;

            SELECT @RowCnt = COUNT(1) 
             FROM    dbo.t_result_SchoolItems_exam result
             JOIN    dbo.t_result_VerificationList_exam con
             ON      result.result_control_id = con.result_control_id
             AND     con.exam_division_code = result.exam_division_code
             JOIN    dbo.t_result_name_exam n
             ON      con.result_name_id = n.result_name_id
             JOIN    dbo.t_result_Active_Verification_id_exam curr
             ON      con.result_control_id = curr.result_control_id
             AND     curr.exam_division_code = result.exam_division_code
             WHERE   n.result_name = 'PatternD book'
             AND     con.exam_region_code = @exam_region_code
             AND     con.exam_bus_date = @std_date
             AND     result.exam_division_code = @exam_Source_Section_division


             --ORDER BY result.system_id, result.Roll_ID, result.Ce_value_local_ledgerK, result.due_local_ledgerK, result.cash_amount_local_ledgerK
             OPTION (RECOMPILE);

            SET @rows_returned = @RowCnt; 


     END TRY


     BEGIN CATCH
         SELECT  @Raiserror = 300000 + error_number() ,
                 @ErrorSeverity = error_severity() ,
                 @ErrorState = error_state() ,
                 @Msg = @ProcName + ': ' + isnull ( error_message() , @Msg ) + ' , Error Number = ' + isnull ( convert ( varchar , error_number()) , '' )
                          + ' , Error Line = ' + isnull ( convert ( varchar , error_line()) , 'N/A' );

         RAISERROR (@Msg, @ErrorSeverity, @ErrorState);
          RETURN @Raiserror;
     END CATCH;


GO

--||--**-- --||--**-- --||--**-- --||--**-- --||--**--

1 Ответ

0 голосов
/ 15 февраля 2019

Не видя код как для задачи скрипта, так и для хранимой процедуры, довольно сложно точно определить, что не так, но я возьму некоторые трещины, как это.

В вашей задаче сценария вы выполняетехранимая процедура, и она возвращает набор результатов, а также выходной параметр.Где-то у вас есть NULL из хранимой процедуры.NULL в «вещи» базы данных преобразуется в сложный тип в рамках .NET.Я не могу написать

int i = null;

, потому что моя переменная, i, является примитивным типом.Это должно иметь значение, которое имеет смысл.Я мог бы написать

int? i = null;

, потому что ? указывает на это обнуляемый тип.В языке SQL такой сложности нет, поэтому он рад присвоить переменной значение null.

DECLARE @i int = NULL;

В вашей задаче сценария вам необходимо проверить все места, к которым вы пытаетесь получить доступ к вашему DataRow / DataTable / DataSetobject, а также свойство Parameters.Value выходного параметра.

Почему это работает после первого раза?

Не могу сказать.Возможно, в хранимой процедуре есть встроенная логика, чтобы «получить все данные с момента последнего выполнения», и новый запуск не имеет значений NULL в некотором поле.Это также может объяснить, почему файл частично заполнен.Вполне вероятно, что если вы поймете, что эта строка была в базе данных в тот момент, когда вы к ней обращались, вы найдете там значение NULL.

Справочное чтение

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...