Настраиваемая задача рабочего процесса SSIS - PullRequest
3 голосов
/ 09 мая 2019

У меня есть тонна контейнеров, которые следуют той же основной посылке:

enter image description here

Когда я извлекаю данные из удаленной базы данных, я сначала очищаюсьтаблицу коллекторов, скопировать данные из удаленной БД в коллектор, сосчитать строки в коллекторе, и, если строк достаточно, я объединяюсь в реальную таблицу.Если нет, я отправляю электронное письмо с сообщением об ошибке.

Вместо того, чтобы повторять это снова и снова, я хотел бы создать собственный компонент.Я думаю, что это всего лишь компонент фильтра, который я бы сделал, но в чем я не уверен, так это в том, как скопировать фрагмент Data Flow Task.Есть ли хорошие примеры, на которые кто-нибудь мог бы указать мне, или даже просто дать мне знать, что я хочу сделать, невозможно?

1 Ответ

2 голосов
/ 09 мая 2019

Когда я вижу подобные проблемы, Biml имеет тенденцию предлагать самый низкий барьер для создания простого, повторяемого решения.Biml бесплатен, все, что вам нужно, это регистрационное письмо и установка BimlExpress в любую версию Visual Studio / SSDT, с которой вы работаете.

Я предполагаю, что собираюсь собратьданные из таблицы AdventureWorks2014 Sales.Currency и перенести их в таблицу в базе данных tempdb с именем dbo.SalesCurrency.

Я определил ее как

CREATE TABLE dbo.SalesCurrency
(
    CurrencyCode nchar(3) NOT NULL
,   Name nvarchar(50) NOT NULL
,   ModifiedDate datetime NOT NULL
);

Учитывая это, давайте рассмотрим некоторые концепции Biml.Biml - это основанный на XML диалект, который описывает артефакты бизнес-аналитики (а затем и некоторые).Если вы когда-либо занимались классической разработкой ASP с использованием сочетания сценариев и тегов, это схожая концепция, но гораздо приятнее из-за интеграции .NET.

  • <# #> это многострочный блок
  • <#= #> это выражение в одну строку

Отлично, как мне его использовать?Предполагая, что вы установили BimlExpress, откройте проект SSIS и щелкните правой кнопкой мыши раздел Project и выберите Add New Biml File.Сделайте это дважды, и мы переименуем второе.Первый - это драйвер, второй - рабочий.

Brains biml

<Biml xmlns="http://schemas.varigence.com/biml.xsd">
    <Connections>
        <OleDbConnection Name="Source" ConnectionString="Data Source=localhost\dev2017;Initial Catalog=AdventureWorks2014;Provider=SQLNCLI11.0;Integrated Security=SSPI;" />        
        <OleDbConnection Name="Target" ConnectionString="Data Source=localhost\dev2017;Initial Catalog=tempdb;Provider=SQLNCLI11.0;Integrated Security=SSPI;" />        
    </Connections>
<#
string sourceQuery = "SELECT * FROM Sales.Currency;";
string targetSchemaTable = "[dbo].[SalesCurrency]";
string templateName = "so_56050574_include.biml";
dynamic customOutput;
#>
    <Packages>
        <#= CallBimlScriptWithOutput(templateName, out customOutput, sourceQuery, targetSchemaTable) #>
    </Packages>
</Biml>

Первая строка - это просто пространство имен xml.

Следующий блок,Коллекции соединений Я определяю мои соединения с источником и цельюЯ очень креативен и назвал их Source и Target

Следующие строки очень похожи на C #, потому что они есть.Я определяю исходный запрос, полное имя целевой таблицы, включенные квадратные скобки и имя моего файла шаблона.Последняя переменная customOutput здесь не используется, но это пакет, который позволяет мне передавать информацию обратно из файла шаблона, а именно - имя созданного им пакета служб SSIS.

Затем я определяю коллекцию Packages исделать одну упаковкуПакет, который я создаю, определяется тем, что я посылаю CallBimlScriptWithOutput, и затем я использую переменные, которые я только что определил.

Это выглядит сложно, но это не так.Мне нравится этот подход, потому что вместо жесткого кодирования этих значений в моей программе драйверов, он позволяет мне использовать подход, основанный на метаданных, к разработке.Я мог бы найти эти значения из электронной таблицы, списка Sharepoint, веб-сервиса, что бы я ни чувствовал (или мой клиент предлагает в качестве хранилища).

Worker biml

Я называю этот файл so_56050574_include.bimlи хотя там много текста, это довольно просто.

Первая строка помогает Intellisense во время проектирования Biml.Следующие две строки указывают, что эти переменные будут передаваться - как вызов функции.Я смогу использовать их как переменную .NET в пределах области действия этого файла.

Следующие несколько строк немного странны, но SSIS не любит дублированные имена и не любит "плохие "персонажи в именах.Я указываю, что имя пакета будет Populate Collector, и затем я делаю целевую таблицу безопасной для SSIS.Внизу файла вы увидите, что я создал крошечный метод с именем MakeSsisSafeName, который я использую для очистки имени пакета.

Я создаю пакет и называю его добрым именем.Этот пакет имеет контейнер.Внутри контейнера я создаю несколько переменных SSIS, которые мне понадобятся для моей работы.В этом контейнере есть задачи «Выполнить задачу SQL» -> «Задача потока данных» -> «Выполнить задачу SQL» -> «Выполнить задачу SQL» -> «Задача отправки почты»

<#@ template designerbimlpath="/Biml/Packages" #>
<#@ property name="SourceQuery" type="string" #>
<#@ property name="TargetSchemaTable" type="string" #>

<#
string packageName = string.Format("Populate Collector {0}", MakeSsisSafeName(TargetSchemaTable));
CustomOutput.PackageName = packageName;
#>
<Package Name="<#= packageName #>" ConstraintMode="Linear">
    <Tasks>
        <Container Name="SEQC Collector" ConstraintMode="Parallel">
            <Variables>
                <Variable Name="RowCount" DataType="Int64">0</Variable>
                <Variable Name="QueryEmpty" DataType="String">TRUNCATE TABLE <#=TargetSchemaTable#></Variable>
                <Variable Name="QueryCount" DataType="String">SET NOCOUNT ON; SELECT COUNT_BIG(1) AS rc FROM <#=TargetSchemaTable#></Variable>
                <Variable Name="QuerySource" DataType="String"><#=SourceQuery#></Variable>
                <Variable Name="TargetSchemaTable" DataType="String"><#=TargetSchemaTable #></Variable>
            </Variables>
            <Tasks>
                <ExecuteSQL Name="SQL Empty Collector Table" ConnectionName="Target">
                    <VariableInput VariableName="User.QueryEmpty" />
                </ExecuteSQL>
                <Dataflow Name="DFT Populate Collector Table">
                    <Transformations>
                        <OleDbSource Name="OLESRC Query" ConnectionName="Source">
                            <VariableInput VariableName="User.QuerySource" />
                        </OleDbSource>
                        <OleDbDestination Name="OLEDST Target" ConnectionName="Target">
                            <TableFromVariableOutput VariableName="User.TargetSchemaTable" />
                        </OleDbDestination>
                    </Transformations>
                    <PrecedenceConstraints>
                        <Inputs>
                            <Input OutputPathName="SQL Empty Collector Table.Output" EvaluationValue="Success" />
                        </Inputs>
                    </PrecedenceConstraints>
                </Dataflow>
                <ExecuteSQL Name="SQL Count Collector Table Rows" ConnectionName="Target" ResultSet="SingleRow">
                    <VariableInput VariableName="User.QueryCount" />
                    <Results>
                        <Result Name="0" VariableName="User.RowCount" />
                    </Results>
                    <PrecedenceConstraints>
                        <Inputs>
                            <Input OutputPathName="DFT Populate Collector Table.Output" EvaluationValue="Success" />
                        </Inputs>
                    </PrecedenceConstraints>
                </ExecuteSQL>
                <ExecuteSQL Name="SQL Merge Collector Data" ConnectionName="Target">
                    <DirectInput>SELECT 1; -- simulate merge</DirectInput>
                        <PrecedenceConstraints>
                            <Inputs>
                                <Input OutputPathName="SQL Count Collector Table Rows.Output" EvaluationOperation="ExpressionAndConstraint" EvaluationValue="Success" Expression="@[User::RowCount] &gt; 0" />
                            </Inputs>
                        </PrecedenceConstraints>
                </ExecuteSQL>
                <!--
                <SendMail Name="Send Mail" ToLine="Foo@bar.com" ConnectionName="Target" Subject="Subject line">
                    <DirectInput>Body here, I think</DirectInput>
                        <PrecedenceConstraints>
                            <Inputs>
                                <Input OutputPathName="SQL Count Collector Table Rows.Output" EvaluationOperation="ExpressionOrConstraint" EvaluationValue="Success" Expression="@[User::RowCount] == 0" />
                            </Inputs>
                        </PrecedenceConstraints>
                </SendMail>
                -->
                <ExecuteSQL Name="SQL Pretend I send mail" ConnectionName="Target">
                    <DirectInput>SELECT 2; -- simulate merge</DirectInput>
                        <PrecedenceConstraints>
                            <Inputs>
                                <Input OutputPathName="SQL Count Collector Table Rows.Output" EvaluationOperation="ExpressionAndConstraint" EvaluationValue="Success" Expression="@[User::RowCount] ==0" />
                            </Inputs>
                        </PrecedenceConstraints>
                </ExecuteSQL>
            </Tasks>
        </Container>
    </Tasks>

</Package>

<#+
private static string MakeSsisSafeName(string name)
{
    return name.Replace("/", "_").Replace("\\", "_").Replace(":", "_").Replace("[", "_").Replace("]", "_").Replace(".", "_").Replace("=", "_").Trim();
}
#>

Щелкните правой кнопкой мыши файл мозгов BimlScript и выберите «Создать пакет служб SSIS».

Biml create package

Это должно создать пакет, подобный этому, и эй, это работает!

Results

Что не покрыто

Я не знаю, как вы на самом деле используете это.Возможно, у вас есть один большой пакет с большим количеством контейнеров, и ваша цель - просто нажать кнопку и добавить еще один контейнер шаблонов.Бимл не будет этого делать.Он не объединяет два пакета служб SSIS - он накладывает один с текущим определением.Но, как я определил все это, вы сможете скопировать сгенерированный Контейнер и вставить его в существующий пакет служб SSIS - при условии, что у него есть два соединения с именами Source и Target.

Соединения также могут быть сложными.Если вы собираете данные с N исходных серверов, вы, вероятно, захотите, чтобы циклический механизм изменял значение источника.Это не сложно.Но если исходные данные, которые вы извлекаете для каждого Collector, имеют различную подпись, то вам нужна каждая сделанная на заказ задача Data Flow.

Отправка электронной почты.У меня нет удобного SMTP-соединения, поэтому я предпочитаю, как будет выглядеть Send Mail, а затем закомментировал его <!-- ... --> Вам нужно будет добавить Connection для вашего SMTP-сервера в пакет мозгов и затем настроитьзадача SendMail использовать его.А затем удалите мою задачу «SQL Pretend I Send Mail».

Наконец, вы заметите, что имена повторяются в рабочем Biml.Это говорит двигателю, как все должно быть подключено.Если вам не нравится то, что я назвал, вам нужно изменить это в двух местах.Поиск и замена будут полезны в этом;)

Вопрос, заданный о пользовательских задачах рабочего процесса - ответьте на него

Отлично.Это отстой.Вещи DataFlow попадают в COM-объекты, и с ними неудобно работать.Когда вы предоставляете запрос или исходную таблицу, вам нужно проверить метаданные, добавить / удалить столбцы и многое другое, что плохо документировано и требует много работы.И это просто создание «обычного» пакета через интерфейсы.Как только вы решите эту проблему, вы посмотрите на инкапсуляцию этой логики в пользовательский компонент, который раньше документировался с достаточным количеством примеров в Codeplex, но сейчас он мертв, и я не знаю, был ли он перенесен в github.Да, и пользовательские задачи и компоненты, в частности, зависят от версии, так что вы можете использовать различные двоичные файлы, чтобы получить dll для каждого.И тогда вам, вероятно, потребуется создать компоненты пользовательского интерфейса, чтобы помочь людям настроить задачу / компонент служб SSIS.И тогда вам нужно будет заботиться о том, чтобы доставить и установить его на компьютер каждого разработчика.И установка сервера.

Или я могу определить его один раз через Biml и все будет сделано.

...