TL;DR
Что такое код EzAPI для использования источника OLE DB с режимом доступа к данным из "команды SQL из переменной" и назначения переменной?
Преамбула
Раз в месяц нам нужно обновить наш публичный тестовый сайт с помощью подмножеств производственных данных. Мы определили, что для наших нужд решение SSIS наилучшим образом подходит для решения этой задачи.
Моя цель - систематически строить большое количество (100+) пакетов "репликации". EzAPI является дружественной оболочкой для объектной модели SSIS, и это похоже, отличный способ сохранить щелчки мыши.
Я хотел бы, чтобы мои пакеты выглядели как
- Variable - "tableName"; [Схема]. [TableName]
- Переменная - "sourceQuery"; SELECT * FROM [Schema]. [TableName]
- DataFlow - "Replicate Schema_TableName"
-
- Источник OLE DB - "Src Schema_TableName"; Режим доступа к данным: команда SQL из переменной; Имя переменной:
User::sourceQuery
- Источник OLE DB - "Src Schema_TableName"; Режим доступа к данным: команда SQL из переменной; Имя переменной:
-
- Назначение OLE DB - "Dest Schema_TableName"; Таблица или представление имени переменной - быстрая загрузка; Имя переменной - User:: tableName
код
Это код для моей таблицы для репликации таблицы.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SqlServer.SSIS.EzAPI;
using Microsoft.SqlServer.Dts.Runtime;
namespace EzApiDemo
{
public class TableToTable : EzSrcDestPackage<EzOleDbSource, EzSqlOleDbCM, EzOleDbDestination, EzSqlOleDbCM>
{
public TableToTable(Package p) : base(p) { }
public static implicit operator TableToTable(Package p) { return new TableToTable(p); }
public TableToTable(string sourceServer, string database, string table, string destinationServer) : base()
{
string saniName = TableToTable.SanitizeName(table);
string sourceQuery = string.Format("SELECT D.* FROM {0} D", table);
// Define package variables
this.Variables.Add("sourceQuery", false, "User", sourceQuery);
this.Variables.Add("tableName", false, "User", table);
// Configure DataFlow properties
this.DataFlow.Name = "Replicate " + saniName;
this.DataFlow.Description = "Scripted replication";
// Connection manager configuration
this.SrcConn.SetConnectionString(sourceServer, database);
this.SrcConn.Name = "PROD";
this.SrcConn.Description = string.Empty;
this.DestConn.SetConnectionString(destinationServer, database);
this.DestConn.Name = "PREPROD";
this.DestConn.Description = string.Empty;
// Configure Dataflow Source properties
this.Source.Name = "Src " + saniName;
this.Source.Description = string.Empty;
this.Source.SqlCommand = sourceQuery;
// Configure Dataflow Destination properties
this.Dest.Name = "Dest " + saniName;
this.Dest.Description = string.Empty;
this.Dest.Table = table;
this.Dest.FastLoadKeepIdentity = true;
this.Dest.FastLoadKeepNulls = true;
this.Dest.DataSourceVariable = this.Variables["tableName"].QualifiedName;
this.Dest.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD_VARIABLE;
this.Dest.LinkAllInputsToOutputs();
}
/// <summary>
/// Sanitize a name so that it is valid for SSIS objects.
/// Strips []/\:=
/// Replaces . with _
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static string SanitizeName(string name)
{
string saniName = name.Replace("[", String.Empty).Replace("]", string.Empty).Replace(".", "_").Replace("/", string.Empty).Replace("\\", string.Empty).Replace(":", string.Empty);
return saniName;
}
}
}
Вызов выглядит как TableToTable s2 = new TableToTable(@"localhost\localsqla", "AdventureWorks", "[HumanResources].[Department]", @"localhost\localsqlb");
, и он создает пакет, который делает то, что я хочу, за исключением использования переменной в источнике.
Проблема
Вышеприведенный код предоставляет режим доступа в виде SQL-запроса, и запрос встроен в источник OLE. Желание использовать "SQL Command From Variable" и эту переменную @[User::sourceQuery]
То, что я застрял, - это использовать переменную в источнике.
Это должно быть простой вопрос: присваивать что-то вроде
this.Source.DataSourceVariable = this.Variables["sourceQuery"].QualifiedName;
this.Source.AccessMode = AccessMode.AM_SQLCOMMAND_VARIABLE;
В результате получается правильный режим доступа к данным, но переменная не заполняется.
Вы можете заметить, что я выполняю аналогичный шаг в пункте назначения, который делает принимает переменную и работает "правильно".
this.Dest.DataSourceVariable = this.Variables["tableName"].QualifiedName;
this.Dest.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD_VARIABLE;
Что не работает
Выделите сделанные мной перестановки
this.Source.AccessMode = AccessMode.AM_OPENROWSET;
Результаты в режиме доступа к данным, заданные в таблице или в представлении, и имя таблицы или вид пуст.
this.Source.AccessMode = AccessMode.AM_OPENROWSET_VARIABLE;
Результаты в режиме доступа к данным, установленные в "Таблица или представление переменной имени", и имя переменной - sourceQuery. Очень близко к тому, что я хочу, кроме того, что режим доступа неверен. Если бы этот пакет работал, он бы взорвался, так как OpenRowSet ожидал бы прямого имени таблицы.
this.Source.AccessMode = AccessMode.AM_SQLCOMMAND;
Результаты в режиме доступа к данным установлены в "SQL Command", а текст команды SQL - "User:: sourceQuery". То, что буквальное значение имени переменной так правильно, но поскольку режим доступа неверен, т работы.
this.Source.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD;
this.Source.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD_VARIABLE;
Niether - это правильные режимы доступа, так как они предназначены для адресатов (я все еще их пробовал, но они не работали должным образом).
В этот момент я подумал, что попытаюсь работать в обратном направлении, создав пакет, в котором есть источник OLE DB, определенный как я хочу, и затем проверяю свойства исходного объекта.
Application app = new Application();
Package p = app.LoadPackage(@"C:\sandbox\SSISHackAndSlash\SSISHackAndSlash\EzApiPackage.dtsx", null);
TableToTable to = new TableToTable(p);
Мой код установил как SqlCommand, так и DataSourceVarible с переменным квалифицированным именем. Я снял changeet 65381 и скомпилировал это (после исправления некоторых ссылок на DLL-серверы SQL Server 2012) в надежде, что, возможно, было исправление с момента создания 30 декабря 2008 года, но безрезультатно.
Я нашел ошибку в своем коде, или я просто что-то пропустил?