2016-03-16 61 views
1

我創建了一個SSIS自定義數據流組件,它執行將日期從COBOL主機日期類型(格式爲CYYMMDD)轉換爲SQL Server支持的格式YYYYMMDD。有錯誤行,因爲傳入的COBOL格式化日期可能是無效日期(即2-29-2015,4-31-2016,9-31-2010等)。這些不良日期來自用戶派生的輸入字段,它們沒有日期掩碼,因爲應用程序屬於第三方數據供應商,所以我無法添加日期掩碼。SSIS自定義數據流組件 - 重定向錯誤行

我的問題:

自定義組件不會重定向錯誤行。我發現在MSDN上一個帖子,介紹如何重新引導錯誤行:

https://msdn.microsoft.com/en-us/library/ms136009.aspx

我用這個代碼作爲指導,並修改它適合我的是能夠執行在多個選擇的輸入列的需要( MS的例子只考慮一個輸入列)。當我執行該過程時,出現以下兩個錯誤:

[ConvertCobolDates [2]]錯誤:System.ArgumentException:值不在預期範圍內。 at Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSBuffer100.DirectErrorRow(Int32 hRow,Int32 lOutputID,Int32 lErrorCode,Int32 lErrorColumn) at Microsoft.SqlServer.Dts.Pipeline.PipelineBuffer.DirectErrorRow(Int32 outputID,Int32 errorCode,Int32 errorColumn ) 在SSIS.Convert.CobolDate.DataFlow.ConvertCobolDateDataFlow.ProcessInput(的Int32 inputID,PipelineBuffer緩衝液) 在Microsoft.SqlServer.Dts.Pipeline.ManagedComponentHost.HostProcessInput(IDTSManagedComponentWrapper100包裝,的Int32 inputID,IDTSBuffer100 pDTSBuffer,IntPtr的bufferWirePacket) [SSIS .Pipeline]錯誤:SSIS錯誤代碼DTS_E_PROCESSINPUTFAILED。組件「ConvertCobolDates」(2)上的ProcessInput方法在處理輸入「Input」(4)時失敗,錯誤代碼爲0x80070057。標識的組件從ProcessInput方法返回錯誤。該錯誤是特定於組件的,但錯誤是致命的,並且會導致數據流任務停止運行。在此之前可能會發布錯誤消息,提供有關失敗的更多信息。

此外,我不知道是否缺少代碼來專門重定向輸出,或者如果錯誤處理不正確 - 它不會顯示在「配置錯誤輸出」屏幕中。任何援助非常感謝! enter image description here

注意:我懷疑錯誤出現在以下位置之一:ProvideComponentProperties或ProcessInput。

public override void ProvideComponentProperties() 
    { 
     try 
     { 
      // Perform the base class' method 
      base.ProvideComponentProperties(); 

      // Start out clean, remove anything put on by the base class 
      base.RemoveAllInputsOutputsAndCustomProperties(); 

      // Set component information 
      ComponentMetaData.Name = "ConvertCobolDates"; 
      ComponentMetaData.Description = "Data Flow task that converts COBOL date types into SQL Server Date types for each row flowing through the component."; 
      ComponentMetaData.ContactInfo = "Contact Info."; 
      ComponentMetaData.UsesDispositions = true; // As a rule, components should support error dispositions - they make it easier to troubleshoot problems with the data 

      // Create input objects. This allows the custom component to have a 'Success' input data flow line 
      IDTSInput100 input = ComponentMetaData.InputCollection.New(); 
      input.Name = "Input"; 
      input.ErrorRowDisposition = DTSRowDisposition.RD_RedirectRow; // Use RD_RedirectRow is ComponentMetaData.UsesDispositions = true. Otherwise, use RD_NotUsed 
      input.ErrorOrTruncationOperation = "Either a bad date has been detected or an input column(s) has been selected that does not contain dates."; 

      // Create output objects. This allows the custom component to have a 'Success' output data flow line 
      IDTSOutput100 output = ComponentMetaData.OutputCollection.New(); 
      output.Name = "Output"; 
      output.SynchronousInputID = input.ID; //Synchronous transformation 
      output.ExclusionGroup = 1; 

      // Create output objects. This allows the custom component to have a 'Error' output data flow line 
      IDTSOutput100 errorOutput = ComponentMetaData.OutputCollection.New(); 
      errorOutput.IsErrorOut = true; 
      errorOutput.Name = "ErrorOutput"; 
      errorOutput.SynchronousInputID = input.ID; 
      errorOutput.ExclusionGroup = 1; 
     } 
     catch (Exception ex) 
     { 
      bool bolCancel = false; 
      ComponentMetaData.FireError(0, ComponentMetaData.Name, ex.Message, "", 0, out bolCancel); 
      throw; 
     } 
    } 

    public override void ProcessInput(int inputID, PipelineBuffer buffer) 
    { 
     IDTSInput100 input = ComponentMetaData.InputCollection.GetObjectByID(inputID); 

     // This code assumes the component has two outputs, one the default, 
     // the other the error output. If the intErrorOutputIndex returned from GetErrorOutputInfo 
     // is 0, then the default output is the second output in the collection. 
     int intDefaultOutputID = -1; 
     int intErrorOutputID = -1; 
     int intErrorOutputIndex = -1; 
     int intErrorColumnIndex = -1; 
     bool bolValidDate = false; 

     GetErrorOutputInfo(ref intErrorOutputID, ref intErrorOutputIndex); 

     if (intErrorOutputIndex == 0) 
      intDefaultOutputID = ComponentMetaData.OutputCollection[1].ID; 
     else 
      intDefaultOutputID = ComponentMetaData.OutputCollection[0].ID; 

     // Process each incoming row 
     while (buffer.NextRow()) 
     { 
      try 
      { 
       for (int i = 0; i < inputBufferColumnIndex.Length; i++) 
       { 
        if (!buffer.IsNull(inputBufferColumnIndex[i])) 
        { 
         // Get the name of the current column that is being processed 
         string strColName = this.ComponentMetaData.InputCollection[0].InputColumnCollection[i].Name; 

         // Get the current row number that is being processed 
         int intCurRow = buffer.CurrentRow + 2;  // Buffer.CurrentRow is zero bounded and the first row is a header row, which is skipped. Adjust by two to account for this 

         // Ideally, your code should detect potential exceptions before they occur, rather 
         // than having a generic try/catch block such as this. However, because the error or truncation implementation is specific to each component, 
         // this sample focuses on actually directing the row, and not a single error or truncation. 

         // Get the ID of the PipelineBuffer column that may cause an error. This is required for redirecting error rows 
         intErrorColumnIndex = this.ComponentMetaData.InputCollection[0].InputColumnCollection[i].ID; 

         string strCobolDate = buffer.GetString(inputBufferColumnIndex[i]); 
         string strConvertedCobolDate = ConvertCobolDate(strCobolDate, strColName, intCurRow); 
         DateTime dtConvertedSQLDate; 

         // Validate that the date is correct. This detects bad dates (e.g., 2-30-2016, 4-31-2015, etc.) that are inputted from the user 
         // Throw an error if the date is bad 
         bolValidDate = DateTime.TryParse(strConvertedCobolDate, out dtConvertedSQLDate); 
         if (!bolValidDate) 
         { 
          // Validation failed, throw an exception and redirect the error row 
          throw new Exception(); 
         } 
         else if (bolValidDate) 
         { 
          // validation passed. Direct the column back to its corresponding row within the pipeline buffer 
          buffer[inputBufferColumnIndex[i]] = dtConvertedSQLDate.ToShortDateString(); 
         } 
        } 
       } 

      // Unless an exception occurs, direct the row to the default 
      buffer.DirectRow(intDefaultOutputID); 
      } 
      catch(Exception) 
      {      
       // Has the user specified to redirect the row? 
       if (input.ErrorRowDisposition == DTSRowDisposition.RD_RedirectRow) 
       { 
        // Yes, direct the row to the error output. 
        buffer.DirectErrorRow(intErrorOutputID, 0, intErrorColumnIndex); 
       } 
       else if (input.ErrorRowDisposition == DTSRowDisposition.RD_FailComponent || input.ErrorRowDisposition == DTSRowDisposition.RD_NotUsed) 
       { 
        // No, the user specified to fail the component, or the error row disposition was not set. 
        throw new Exception("An error occurred, and the DTSRowDisposition is either not set, or is set to fail component."); 
       } 
       else 
       { 
        // No, the user specified to ignore the failure so direct the row to the default output. 
        buffer.DirectRow(intDefaultOutputID); 
       } 
      } 
     } 
    } 

回答

1

後從朋友處有些疼痛跑馬圈地研究和幫助下,問題已經被確定 - 0的errorCode(在MSDN文章中,我previosuly發佈指定)正在傳遞到DirectErrorRow功能是不正確[它實際上是一個負數(在這種情況下:-1071628258)]。這是一個難以解決的錯誤,因爲編譯器正在輸出泛型越界錯誤,而未指定超出界限的參數和值(請參見下文)。

  • 'System.ArgumentException:值不在預期的範圍內。' ...消息截斷,以減少後期長度

我認爲編譯器錯誤指的是實際的錯誤的日期,它無法轉換,所以我花了我所有的時間專注於intErrorColumnIndex,這MSDN文章列表如下:

  • // TODO:添加代碼以包含intErrorColumnIndex。

我認爲Microsoft提供的errorCode爲0是正確的。在預感上,我的朋友說要嘗試檢索實際的錯誤代碼,並且工作正常!因此,errorCode可能在負無窮到-1之間。微軟關於指導錯誤行的MSDN文章需要更正。

我:1

微軟:0

的解決方案是如在catch塊如下:

  catch(Exception) 
      {      
       // Has the user specified to redirect the row? 
       if (input.ErrorRowDisposition == DTSRowDisposition.RD_RedirectRow) 
       { 
        // Yes, get the error code 
        int DTS_E_ERRORTRIGGEREDREDIRECTION = -1; 
        unchecked 
        { 
         DTS_E_ERRORTRIGGEREDREDIRECTION = (int)0xC020401E; 
        } 

        // Direct the row to the error output 
        buffer.DirectErrorRow(intErrorOutputID, DTS_E_ERRORTRIGGEREDREDIRECTION, intErrorColumnIndex); 
       } 
       else if (input.ErrorRowDisposition == DTSRowDisposition.RD_FailComponent || input.ErrorRowDisposition == DTSRowDisposition.RD_NotUsed) 
       { 
        // No, the user specified to fail the component, or the error row disposition was not set 
        throw new Exception("An error occurred, and the DTSRowDisposition is either not set or is set to fail component."); 
       } 
       else 
       { 
        // No, the user specified to ignore the failure so direct the row to the default output 
        buffer.DirectRow(intDefaultOutputID); 
       } 
      } 
相關問題