c# - 在脚本任务中向字典添加重复键时出错

标签 c# sql-server ssis ssis-2012

该脚本已经运行了很长时间,但突然开始崩溃

Error: 0x0 at (SCR) GetLineageIDs, ProcessDataFlowTask error:: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at ST_b90e02c5aa5e4a7a992a1a75c6255cfa.ScriptMain.ProcessDataFlowTask(TaskHost currentDataFlowTask)

目标是将 lineageID 映射到我的 SSIS 包中的实际列名(2012 年,因此没有 2016 年的沿袭功能)。

我知道我正在尝试在下面的脚本中添加一个已经添加到我的字典中的键,我不确定它是如何以及为什么突然开始出错的,下面是完整的脚本。我想我的 ProcessDataFlowTask 方法中需要某种 if block ,非常感谢收到任何指示以及为什么突然出现重复键错误的解释?

namespace ST_b90e02c5aa5e4a7a992a1a75c6255cfa
{
    /// <summary>
    /// ScriptMain is the entry point class of the script.  Do not change the name, attributes,
    /// or parent of this class.
    /// </summary>
    [Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
    public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
    {


        Dictionary<int, string> lineageId = null;

        public void Main()
        {

            try
            {
                // Grab the executables so we have to something to iterate over, and initialize our lineageIDs list
                // Why the executables?  Well, SSIS won't let us store a reference to the Package itself...
                Dts.Variables["User::execsObj"].Value = ((Package)Dts.Variables["User::execsObj"].Parent).Executables;
                Dts.Variables["User::lineageIds"].Value = new Dictionary<int, string>();
                lineageId = (Dictionary<int, string>)Dts.Variables["User::lineageIds"].Value;

                Executables execs = (Executables)Dts.Variables["User::execsObj"].Value;

                ReadExecutables(execs);

                Dts.TaskResult = (int)ScriptResults.Success;

            }
            catch (Exception ex)
            {
                //An error occurred.  
                Dts.Events.FireError(0, "SSIS variable read error:", ex.Message + "\r" + ex.StackTrace, String.Empty, 0);
                Dts.TaskResult = (int)ScriptResults.Failure;
            }  

        }

        private void ReadExecutables(Executables executables)
        {

            try
            {

                foreach (Executable pkgExecutable in executables)
                {
                    if (object.ReferenceEquals(pkgExecutable.GetType(), typeof(Microsoft.SqlServer.Dts.Runtime.TaskHost)))
                    {
                        TaskHost pkgExecTaskHost = (TaskHost)pkgExecutable;
                        if (pkgExecTaskHost.CreationName.StartsWith("SSIS.Pipeline"))
                        {
                            ProcessDataFlowTask(pkgExecTaskHost);
                        }
                    }
                    else if (object.ReferenceEquals(pkgExecutable.GetType(), typeof(Microsoft.SqlServer.Dts.Runtime.ForEachLoop)))
                    {
                        // Recurse into FELCs
                        ReadExecutables(((ForEachLoop)pkgExecutable).Executables);
                    }
                }

            }
            catch (Exception ex)
            {
                //An error occurred.  
                Dts.Events.FireError(0, "ReadExecutables error:", ex.Message + "\r" + ex.StackTrace, String.Empty, 0);
                Dts.TaskResult = (int)ScriptResults.Failure;
            }  

        }

        private void ProcessDataFlowTask(TaskHost currentDataFlowTask)
        {

            try
            {

                MainPipe currentDataFlow = (MainPipe)currentDataFlowTask.InnerObject;
                foreach (IDTSComponentMetaData100 currentComponent in currentDataFlow.ComponentMetaDataCollection)
                {
                    // Get the inputs in the component.
                    foreach (IDTSInput100 currentInput in currentComponent.InputCollection)
                        foreach (IDTSInputColumn100 currentInputColumn in currentInput.InputColumnCollection)
                           lineageId.Add(currentInputColumn.ID, currentInputColumn.Name);


                    // Get the outputs in the component.
                    foreach (IDTSOutput100 currentOutput in currentComponent.OutputCollection)
                        foreach (IDTSOutputColumn100 currentoutputColumn in currentOutput.OutputColumnCollection)
                            lineageId.Add(currentoutputColumn.ID, currentoutputColumn.Name);

                }

            }
            catch (Exception ex)
            {
                //An error occurred.  
                Dts.Events.FireError(0, "ProcessDataFlowTask error:", ex.Message + "\r" + ex.StackTrace, String.Empty, 0);
                Dts.TaskResult = (int)ScriptResults.Failure;
            }  


        }
        #region ScriptResults declaration
        /// <summary>
        /// This enum provides a convenient shorthand within the scope of this class for setting the
        /// result of the script.
        /// 
        /// This code was generated automatically.
        /// </summary>
        enum ScriptResults
        {
            Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
            Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
        };
        #endregion

    }


}

最佳答案

如果您在包中的任何数据流中有重复的列名,则会出现“重复键”错误。我之前遇到过这个问题,我通过添加以下 2 个步骤解决了它。

第一步
在 lineageId.Add(...) 的两个实例中对 ProcessDataFlowTask 方法进行以下更改

Remember to use currentOutputColumn.Name instead of currentInputColumn.Name at the second instance

更改自

lineageId.Add(currentInputColumn.ID, currentInputColumn.Name);


strNewID = currentDataFlowTask.Name + "_" + currentInputColumn.ID.ToString();
lineageIDs.Add(strNewID, currentInputColumn.Name);

Basically giving a unique name for the Column Name by adding the Data Flow Name plus the '_' (Underscore) as a prefix.


第 2 步
由于我们在添加到 LineageIDs 集合时修改了列名,因此在比较 Input0_ProcessInputRow 另一个脚本任务中的方法,这是必需的,您没有在上面复制。

    string newColNum = "DataFlowTaskName_" + Row.ErrorColumn.Value.ToString();
    if (lineageIDs.ContainsKey(newColNum))
        Row.ErrorColumnName = lineageIDs[newColNum];


注意:在上面的代码中,DataFlowTaskName_ 是硬编码值,需要替换为第二个脚本任务所在的数据流任务名称,因为它在 Input0_ProcessInputRow 方法中不可用,我们需要硬编码它。

这只是一种方法,也许您可​​以找到另一种处理重复项的方法,我就是这样做的,而且效果很好。


希望这会有所帮助。

关于c# - 在脚本任务中向字典添加重复键时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41759891/

相关文章:

sql-server - 始终加密 : Certificate with thumbprint not found in certificate store

sql-server - 在 Azure Data Studio 中尝试 SQL Notebooks 但在一个单元格中声明的变量未携带到新单元格

c# - Microsoft Visual Studio - 无法在 SSIS 包中打开脚本任务

c# - 32 位和 64 位操作系统中的双字节大小

C#:在 Word 中打开 FileStream 中的 Word 文件以供读取

sql - 应用掩码以格式化 SQL Server 查询/ View 中的字符串

sql - 如何处理 SSAS DMV 元数据中最大字符串长度 255

sql - 安装 SSIS

c# - 一个变量如何同时有两个值?

c# - 有没有办法使用用户名和密码对 Graph API 进行身份验证,而无需在 Azure AD 中注册应用程序