10

tl;博士

使用具有“来自变量的 SQL 命令”的数据访问模式的 OLE DB 源并分配变量的 EzAPI 代码是什么?

前言

每月一次,我们需要使用生产数据的子集刷新我们的公共测试站点。我们已经确定,根据我们的需要,SSIS 解决方案最适合完成这项任务。

我的目标是系统地构建大量(100 多个)“复制”包。EzAPISSIS 对象模型的友好包装器,它似乎是节省鼠标点击的好方法。

我希望我的包裹看起来像

  • 变量 - “tableName”;[架构].[表名]
  • 变量 - “sourceQuery”;SELECT * FROM [Schema].[TableName]
  • 数据流 - “复制 Schema_TableName”
    • OLE DB 源 - “Src Schema_TableName”;数据访问模式:来自变量的 SQL 命令;变量的名称:User::sourceQuery
    • 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'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 Query 的访问模式,并且查询嵌入在 OLE Source 中。它使用“来自变量的 SQL 命令”的愿望以及@[User::sourceQuery] 我坚持的变量是在源代码中使用一个变量。

分配类似的东西应该很简单

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

这会导致选择了正确的数据访问模式,但未填充变量。 ole 数据库源

您可以观察到我在目的地执行了类似的步骤,它确实接受了变量并且“正确”工作。

        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 设置为变量的限定名称。我已经拉下变更集 65381 并对其进行编译(在修复了对 SQL Server 2012 dll 的一些引用之后),希望自 2008 年 12 月 30 日稳定版本以来可能已经修复,但无济于事。

我是否在他们的代码中发现了错误,或者我只是遗漏了一些东西?

4

2 回答 2

12

当前稳定的 EzAPI 版本不支持将变量分配为 OleDB 源属性。我在 CodePlex 上展开了类似的讨论,最终了解了所有这些如何工作的更多信息。

根本问题是当访问模式设置为“来自变量的SQL命令”时,应该设置相关属性“SqlCommandVariable”。目前,代码仅涵盖目标变量。

我的解决方案是下载源代码并修改DataSourceVariableEzComponents.cs 中属性的设置器(变更集 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 回答