SSIS читает переменную System.Object и записывает в нее компонент Script ... Как? - PullRequest
3 голосов
/ 10 февраля 2020

У меня есть пакет служб SSIS, который начинается с задачи сценария, которая инициализирует пустой объект DataTable и присваивает его переменной пользователя. Я добавляю несколько примеров строк, так как я все еще занимаюсь разработкой. Переменная называется: FlatFileBadRowDataTracker в SSIS.

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 через компонент источника плоских файлов) и имеет компонент Script (как преобразование) который определяет, являются ли строки хорошими или плохими. Хорошие строки отправляются на выход «GoodRow», а плохие строки отправляются на «BadRows» из компонента Script. Обычно файл содержит в основном хорошие строки, но некоторые из них имеют ошибки данных (например, в столбце электронной почты есть что-то, что не похоже на адрес электронной почты), и в этом случае компонент должен отправить это в вывод BadRows. Моя цель - записать данные, связанные с ошибками (например, имя столбца с ошибкой данных и некоторое описание вместе с ним) в ту же таблицу данных, которую я создал в задаче сценария ранее.

Я добавил эту переменную в ReadWriteVariables в Свойствах экрана редактора компонентов скрипта. Я использую его в PreExecute(), чтобы получить схему DataTable и присвоить ей dt, которая является локальной переменной, которую я объявил в начале класса.

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

} 

Затем Я пытаюсь добавить данные в dt, как и когда я нахожу связанные с данными ошибки в методе Input0_ProcessInputRow(Input0Buffer Row). После этого в PostExecute() я пытаюсь присвоить dt обратно пользовательской переменной.

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

Однако, когда я запускаю пакет, я получаю эту ошибку (показанную ниже), которая говорит мне, что я не могу использовать переменную в методе PreExecute (). Кажется, я могу использовать его только в методе PostExecute (). Мне нужны существующие данные + схема таблицы данных, в противном случае мне придется пересоздать схему, и я потеряю данные (на данный момент это только тестовые данные, как показано в коде).

enter image description here

Можно ли как-нибудь получить схему + данные объекта DataTable в моем компоненте сценария? Компонент Script также не позволяет мне добавлять переменные в ReadOnlyVariables и ReadWriteVariables. Кажется, я могу добавить его только к одному из них.

Ответы [ 2 ]

3 голосов
/ 11 февраля 2020

Попробуйте использовать распределитель переменных вместо выбора переменной в качестве переменной ReadWrite:

Фаза перед выполнением:

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();

За дополнительной информацией обращайтесь к:

1 голос
/ 11 февраля 2020

О причине, по которой вы получаете такие сообщения об ошибках. Переменные для чтения и записи доступны только при методе PostExecute; Microsoft сделала это, чтобы уменьшить вероятность заторов. Итак, ваше сообщение об ошибке выдается в методе PreExecute.
Рекомендации Хади должны помочь вам получить доступ к вашей переменной RW перед запуском метода Script Component PostExecute.

...