【问题标题】:SSIS read a System.Object variable and write to it in Script Component...How?SSIS 读取一个 System.Object 变量并在脚本组件中写入它......如何?
【发布时间】:2020-02-12 20:32:38
【问题描述】:

我有一个 SSIS 包,它以一个脚本任务开始,它初始化一个空的 DataTable 并将其分配给一个用户变量。我正在添加一些示例行,因为我仍在进行开发。该变量在 SSIS 中称为:FlatFileBadRowDataTracker

public void Main()
{
    // TODO: Add your code here
    string SSISRunStartTimeStamp = DateTime.Now.ToString("yyyyMMddHHmmss");
    Dts.Variables["User::SSISRunStartTimeStamp"].Value = SSISRunStartTimeStamp;
    Dts.Variables["User::FlatFileBadRowDataTracker"].Value = BuildSampleDataTable();


    Dts.TaskResult = (int)ScriptResults.Success;
}

private DataTable BuildSampleDataTable()
{
    DataTable dt = new DataTable();

    // ErrorColumn
    DataColumn errorColumn = new DataColumn("ErrorColumn");
    errorColumn.DataType = System.Type.GetType("System.String");
    errorColumn.DefaultValue = string.Empty;
    dt.Columns.Add(errorColumn);

    // ErrorDescription
    DataColumn errorDescription = new DataColumn("ErrorDescription");
    errorColumn.DataType = System.Type.GetType("System.String");
    errorColumn.DefaultValue = string.Empty;
    dt.Columns.Add(errorDescription);

    // FileName
    DataColumn fileName = new DataColumn("FileName");
    errorColumn.DataType = System.Type.GetType("System.String");
    errorColumn.DefaultValue = string.Empty;
    dt.Columns.Add(fileName);

    // RawData
    DataColumn rawData = new DataColumn("RawData");
    errorColumn.DataType = System.Type.GetType("System.String");
    errorColumn.DefaultValue = string.Empty;
    dt.Columns.Add(rawData);

    // ErrorDescription
    DataColumn dataFlowComponent = new DataColumn("DataFlowComponent");
    errorColumn.DataType = System.Type.GetType("System.String");
    errorColumn.DefaultValue = string.Empty;
    dt.Columns.Add(dataFlowComponent);

    // Populate with some sample data.
    DataRow row;
    for (int i = 1; i < 5; i++)
    {
        row = dt.NewRow();
        row["ErrorColumn"] = "ErrorColumn" + i;
        row["ErrorDescription"] = "ErrorDescription" + i;
        row["FileName"] = "FileName" + i;
        row["RawData"] = "RawData" + i;
        row["DataFlowComponent"] = "SSIS_DataFlowTask_" + i;
        dt.Rows.Add(row);
    }

    return dt;
}

#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

然后我有一个数据流任务,它读取一个文本文件(通过平面文件源组件的 csv)和一个脚本组件(作为转换),它确定行是好还是坏。好的行被发送到脚本组件的“GoodRow”输出,而坏的行被发送到“BadRows”输出。通常一个文件会有大部分是好的行,但少数会有数据错误(例如:email 列有一些不像电子邮件地址的东西),在这种情况下,组件必须将其发送到 BadRows 输出。我的目标是将错误相关数据(例如具有数据错误的列名和一些描述)捕获到我之前在脚本任务中创建的同一个 DataTable 中。

我已经在脚本组件编辑器屏幕的属性下的 ReadWriteVariables 中添加了这个变量。我在PreExecute() 中使用它来获取DataTable 的架构并将其分配给dt,这是我在类开头声明的局部变量。

public override void PreExecute()
{
    base.PreExecute();
    dt = (DataTable)Variables.FlatFileBadRowDataTracker;

} 

然后,当我在Input0_ProcessInputRow(Input0Buffer Row) 方法中发现与数据相关的错误时,我尝试将数据添加到dt。之后,在PostExecute() 中,我尝试将dt 分配回用户变量。

public override void PostExecute()
{
    base.PostExecute();
    Variables.FlatFileBadRowDataTracker = dt;
}

但是,当我运行包时,我得到了这个错误(如下所示),它告诉我我不能在 PreExecute() 方法中使用该变量。看来我只能在 PostExecute() 方法中使用它。我需要数据表的现有数据+模式,否则我将不得不重新创建模式并且我会丢失数据(现在它只是代码中显示的测试数据)。

有什么方法可以在我的脚本组件中获取 DataTable 的架构+数据?脚本组件也不允许我在ReadOnlyVariablesReadWriteVariables 中添加变量。看来我只能将它添加到其中一个。

【问题讨论】:

    标签: c# sql-server ssis etl script-component


    【解决方案1】:

    尝试使用变量分配器,而不是选择变量作为读写变量:

    预执行阶段:

    IDTSVariables100 vars = null;
    VariableDispenser.LockForRead("User::FlatFileBadRowDataTracker");
    VariableDispenser.GetVariables(out vars);
    dt = (DataTable)vars["User::FlatFileBadRowDataTracker"].Value;
    vars.Unlock();
    

    执行后阶段:

    IDTSVariables100 vars = null;
    VariableDispenser.LockForWrite("User::FlatFileBadRowDataTracker");
    VariableDispenser.GetVariables(out vars);
    vars["User::FlatFileBadRowDataTracker"].Value = dt;
    vars.Unlock();
    

    有关其他信息,请参阅:

    【讨论】:

    • 谢谢@Hadi。如果我在同一个数据流任务中的另一个脚本组件中使用相同的方法,这会导致任何锁定冲突吗? Unlock() 之后需要 Lock() 吗?
    • 我不认为你可以在同一个数据流任务中多次使用一个变量,因为该值是在数据流执行结束时提交的(该值不会在数据流)。关于变量锁,我认为它可能会导致冲突,但最好尝试一下。 @gtrivedi
    【解决方案2】:

    关于您收到此类错误消息的原因。读写变量仅在PostExecute 方法中可用;微软这样做是为了减少拥堵的机会。因此,您的错误消息会在 PreExecute 方法中抛出。
    Hadi 的建议应该在运行 Script Component PostExecute 方法之前访问您的 RW 变量。

    【讨论】:

      猜你喜欢
      • 2011-01-18
      • 1970-01-01
      • 2014-01-27
      • 1970-01-01
      • 2014-02-26
      • 1970-01-01
      • 2012-11-07
      • 2015-06-25
      • 2019-09-28
      相关资源
      最近更新 更多