10

tl;dr

「変数からの SQL コマンド」のデータ アクセス モードで OLE DB ソースを使用し、変数を割り当てる EzAPI コードは何ですか?

前文

1 か月に 1 回、公開テスト サイトを運用データのサブセットで更新する必要があります。私たちのニーズには、SSIS ソリューションがこのタスクの達成に最適であると判断しました。

私の目標は、多数 (100 以上) の「複製」パッケージを体系的に構築することです。EzAPIは、 SSIS オブジェクト モデルの親しみやすいラッパーであり、マウス クリックを節約する優れた方法のようです。

パッケージを次のようにしたい

  • 変数 - "テーブル名"; [スキーマ].[テーブル名]
  • 変数 - "sourceQuery"; SELECT * FROM [スキーマ].[テーブル名]
  • DataFlow - 「Schema_TableName を複製」
    • OLE DB ソース - "Src Schema_TableName"; データ アクセス モード: 変数からの SQL コマンド。変数名:User::sourceQuery
    • OLE DB 宛先 - "Dest Schema_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's Source properties
            this.Source.Name = "Src " + saniName;
            this.Source.Description = string.Empty;
            this.Source.SqlCommand = sourceQuery;

            // Configure Dataflow's 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コマンド」を使用したいという願望とその変数@[User::sourceQuery] は、ソースで変数を使用することです。

次のようなものを割り当てるのは簡単なことです

        this.Source.DataSourceVariable = this.Variables["sourceQuery"].QualifiedName;
        this.Source.AccessMode = AccessMode.AM_SQLCOMMAND_VARIABLE;

これにより、正しいデータ アクセス モードが選択されますが、変数は設定されません。 ole db ソース

変数を受け入れて「正しく」機能する宛先で同様の手順を実行することがわかります。

        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 コマンド" に設定され、SQL コマンド テキストが "User::sourceQuery" になります。これは変数名のリテラル値なので正しいことですが、アクセス モードが間違っているため、機能しません。

        this.Source.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD;
        this.Source.AccessMode = AccessMode.AM_OPENROWSET_FASTLOAD_VARIABLE;

これらのいずれも、目的地のための正しいアクセス モードではありません (まだ試してみましたが、期待どおりに動作しませんでした)。

この時点で、必要に応じて定義された OLE DB ソースを含むパッケージを作成し、ソース オブジェクトのプロパティを調べることで、逆方向に作業しようと考えました。

        Application app = new Application();
        Package p = app.LoadPackage(@"C:\sandbox\SSISHackAndSlash\SSISHackAndSlash\EzApiPackage.dtsx", null);
        TableToTable to = new TableToTable(p);

ソース プロパティ

私のコードでは、SqlCommand と DataSourceVarible の両方に変数の修飾名を設定しています。2008 年 12 月 30 日の Stable ビルド以降に修正があったことを期待して、変更セット 65381 を取り出してコンパイルしました (SQL Server 2012 dll への参照を修正した後)。

彼らのコードにバグを見つけたのでしょうか、それとも何か足りないのでしょうか?

4

2 に答える 2

12

EzAPI の現在の安定したビルドは、OleDB ソース プロパティとしての変数の割り当てをサポートしていません。私は CodePlex で同様の議論を開始し、最終的にこれらすべてがどのように機能するかについて詳しく学びました。

根本的な問題は、アクセス モードが「変数からの SQL コマンド」に設定されている場合に、関連するプロパティ「SqlCommandVariable」を設定する必要があることです。現在、コードは宛先変数のみをカバーしています。

私の解決策は、ソース コードをダウンロードし、EzComponents.cs のプロパティのセッターを変更することでしたDataSourceVariable(changeset 65381 の行 1027)。

        set 
        { 
            m_comp.SetComponentProperty("OpenRowsetVariable", value); 
            if (AccessMode == AccessMode.AM_SQLCOMMAND_VARIABLE)
            {
                m_comp.SetComponentProperty("SqlCommandVariable", value); 
            }
            ReinitializeMetaData(); 
        } 

この問題を適切に解決したい場合は、問題に賛成票を投じることができます

于 2012-01-23T15:14:27.337 に答える
2

いろいろ入れ替えてみる

this.Source.DataSourceVariable = this.Variables["sourceQuery"].QualifiedName;

this.Source.AccessMode = AccessMode.AM_SQLCOMMAND_VARIABLE; 

this.Source.AccessMode = AccessMode.AM_SQLCOMMAND_VARIABLE; 

this.Source.DataSourceVariable = this.Variables["sourceQuery"].QualifiedName;

一般的な API よりも順序が重要であることを発見しました。

于 2012-01-19T08:54:28.443 に答える