【问题标题】:What is the EzAPI equivalent for using an OLE DB Source command from variable?从变量中使用 OLE DB 源命令的 EzAPI 等效项是什么?
【发布时间】:2012-01-18 20:07:03
【问题描述】:

tl;博士

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

序言

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

我的目标是系统地构建大量(100 多个)“复制”包。 EzAPI 是 SSIS object model 的友好包装,它似乎是节省鼠标点击的好方法。

我希望我的包裹看起来像

  • 变量 - “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");,它构建了一个包,它可以执行我想要的except,以便在源代码中使用变量。

问题

上面的代码提供了 SQL Query 的访问模式,并且该查询嵌入在 OLE Source 中。它希望使用“来自变量的 SQL 命令”并且该变量是 @[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 命令”,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 日稳定版本以来可能已经修复,但无济于事。

我是否在他们的代码中发现了错误,或者我只是遗漏了什么?

【问题讨论】:

  • 嗨@TheOptimusPrimus 你能帮我理解你的评论吗?你高超的智慧让我感到震惊。这个问答是不是又偷东西了?
  • @TheOptimusPrimus 我还有更多需要投票的答案,但请注意不要烧毁所有声誉。我的一直在上升,所以我认为你做错了

标签: c# ssis ezapi


【解决方案1】:

当前稳定的 EzAPI 版本不支持将变量分配为 OleDB 源属性。我在 CodePlex 上打开了一个类似的 discussion 并最终了解了有关所有这些工作原理的更多信息。

根本问题是相关属性"SqlCommandVariable" should be set when the access mode is set to "SQL Command from Variable." 目前,代码只覆盖目标变量。

我的解决方案是下载源代码并修改 EzComponents.cs 中属性 DataSourceVariable 的设置器(变更集 65381 的第 1027 行)

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

如果您希望正确解决此问题,您可以投票Issue

【讨论】:

  • Serial Downvoter (@TheOptimusPrimus) 我看到您已将其投票为“无用”。我流下了痛苦的眼泪。您能否提供无用的上下文,以便我可以改进这个残暴的排泄物答案?
【解决方案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 更重要。

【讨论】:

  • 我注意到操作的顺序也很重要。以上对你有用还是只是一种预感?我重新安排了操作,但无济于事。
  • 只是一种预感 - 现在我想应该把它作为评论而不是答案。但我现在很好奇,我会试一试并回复你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 2019-03-19
  • 1970-01-01
  • 2019-06-29
  • 2011-04-29
相关资源
最近更新 更多