【问题标题】:Programmatically script SSIS package - Dynamic XML to OLE DB以编程方式编写 SSIS 包 - 动态 XML 到 OLE DB
【发布时间】:2018-02-15 01:55:50
【问题描述】:

我一直在尝试拼凑其他用户如何完成他们的项目,但我的理解仍然有限。

我想获取任何给定的 XML 源,创建一个数据流任务,并将其数据传递到与 XML 文件的表名匹配的 OLE DB 目标。使用可视化工具运行它意味着我无法执行动态数据流任务,因为元数据不会刷新。

我创建了一个创建包的脚本,但是当我在 Visual Studio 中打开包时,它有一个红色 x 表示输入列不能为零。当我向下钻取并查看 OLE DB 目标的映射时,然后单击确定 - 它会为我更正它。我无法弄清楚如何以编程方式做到这一点。

我看到其他人通过使用 foreach 循环并遍历输入列来解决它,但我似乎无法弄清楚。

我还有一个单独的脚本,我试图用它来模仿几个人的脚本,但它有不同的问题。不知道怎么发附件

提前感谢您的帮助:)

编辑

我在尝试 BIML 时得到了积极的反馈,我会的……但我想知道短期内是否有人可以帮助我弄清楚为什么这没有为我的输入填写 ExternalMetaDataColumnId。我在下面发布了我的更新代码,其中的 foreach 循环没有按照我的预期进行。

谢谢 #地区 使用系统; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text; 使用 System.Threading.Tasks; 使用 Microsoft.SqlServer.Dts.Runtime; 使用 Microsoft.SqlServer.Dts.Pipeline.Wrapper; 使用 System.Xml; #endregion

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            #region Initial Setup
            Application a = new Application();
            Package p = new Package();
            TaskHost t = p.Executables.Add("DTS.Pipeline") as TaskHost;
            t.Name = "DataFlow Task";
            t.Description = "Flat File to Database";
            MainPipe mp = t.InnerObject as MainPipe;
            #endregion

            #region Flat File Source in Dataflow Task
            IDTSComponentMetaData100 md = mp.ComponentMetaDataCollection.New(); 
            md.ComponentClassID = "Microsoft.XmlSourceAdapter"; 
            md.Name = "XML Source"; 
            CManagedComponentWrapper wrp = md.Instantiate(); 
            wrp.ProvideComponentProperties(); 

            #endregion

            #region Add connection manager to OLE DB
            ConnectionManager conn = p.Connections.Add("OLEDB");
            conn.Name = "westcoastuserDBO";
            conn.ConnectionString = "Data Source=SERVER;Initial Catalog=DBO;Provider=SQLNCLI11.1;Integrated Security=SSPI;Auto Translate=False;";
            #endregion


            #region XML Source Properties
            wrp.SetComponentProperty("XMLData", @"C:\Users\file.xml");
            wrp.SetComponentProperty("XMLSchemaDefinition", @"C:\Users\file.xsd");
            wrp.SetComponentProperty("AccessMode", 0);
            wrp.SetComponentProperty("UseInlineSchema", false);
            //below does not work
            //wrp.SetComponentProperty("XMLIntegerMapping", 0).TypeConverter = "Microsoft.SqlServer.Dts.Pipeline.XmlSourceAdapter + XMLIntegerMappingConverter";

            wrp.ReinitializeMetaData();
            wrp.ReleaseConnections();
            IDTSComponentMetaData100 md2 = mp.ComponentMetaDataCollection.New();
            md2.ComponentClassID = "Microsoft.OLEDBDestination";
            CManagedComponentWrapper wrp2 = md2.Instantiate();
            wrp2.ProvideComponentProperties();
            md2.Name = "OLE DB Connection";
            md2.UsesDispositions = true;
            md2.Version = 4;
            wrp2.SetComponentProperty("OpenRowset", "dbo.authorizations");
            #endregion

            IDTSPath100 path = mp.PathCollection.New();
            path.AttachPathAndPropagateNotifications(md.OutputCollection[0], md2.InputCollection[0]);

            IDTSInput100 input = md2.InputCollection[0];
            IDTSVirtualInput100 vInput = input.GetVirtualInput();

            //below taken from https://stackoverflow.com/questions/12587709/c-sharp-ssis-data-flow-component-creating-custom-input-columns
            IDTSExternalMetadataColumnCollection100 externalColumnCollection = input.ExternalMetadataColumnCollection;


            // Iterate through the virtual input column collection.
            foreach (IDTSVirtualInputColumn100 vColumn in vInput.VirtualInputColumnCollection)
            {
                // Call the SetUsageType method of the destination
                // to add each available virtual input column as an input column.
                wrp2.SetUsageType(
                   input.ID, vInput, vColumn.LineageID, DTSUsageType.UT_READONLY);
            }

            // Get the destination's default output collection
            IDTSOutputCollection100 outColl = md2.OutputCollection;

            // Iterate through the outputs in default output collection
            foreach (IDTSOutput100 output in outColl)
            {
                // Iterate through the default output columns in the output 
                int count = output.OutputColumnCollection.Count;
                foreach (IDTSOutputColumn100 outputColumn in output.OutputColumnCollection)
                {
                    // Get the output's external metadata column collection
                    IDTSExternalMetadataColumnCollection100 extMetadataColumnColl = output.ExternalMetadataColumnCollection;

                    // Iterate through the external metadata column collection's external metadata columns
                    foreach (IDTSExternalMetadataColumn100 extMetadataColumn in extMetadataColumnColl)
                    {
                        // Call the MapOutPutColumn method of the destination to map
                        // each available output column to an external metadata column 
                        wrp2.MapOutputColumn(
                            output.ID, outputColumn.ID, extMetadataColumn.ID, true);
                    }
                }
            }

            md2.RuntimeConnectionCollection[0].ConnectionManager = DtsConvert.GetExtendedInterface(conn);
            md2.RuntimeConnectionCollection[0].ConnectionManagerID = conn.ID;
            conn.AcquireConnection(null);




            #region Save Package to FileSystem
            string packageXml = @"C:\Users\test.dtsx";
            XmlDocument myPkgDocument = new XmlDocument();
            p.SaveToXML(ref myPkgDocument, null, null);
            a.SaveToXml(packageXml, p, null);
            #endregion
        }
    }
}

【问题讨论】:

标签: c# sql-server xml ssis etl


【解决方案1】:

我认为你没有将输入列映射到 OLEDB Destination 的问题,打开包后,如果你点击 OLEDB Destination 并转到 Mapping 部分,它会根据列的名称自动映射列.其他人使用的 Foreach 循环是循环列并将它们映射到相关的 Destination 列。

关于动态创建SSIS包的文章很多,可以参考一下:

【讨论】:

  • 除了你的回答,如果他想动态创建 SSIS 包,我建议使用 BIML。 bimlscript.com
  • @PlaidDK 我同意这一点
  • 我还不想将其标记为答案,因为在发布问题之前,我已经访问了所有这些页面,但其中一个页面已经访问过——我已经尝试在它通过的地方运行一个 foreach 循环IDTSInputColumn100 列并分配一个 ExternalMetadataColumnId,但它没有成功映射输入列并最终返回“输入列不能为零”的错误。今天我将花一些时间来回顾最后一页,并使用它的示例作为遍历输入列以验证外部元数据的一种方式。如果没有,我将不得不尝试@PlaidDK 关于使用 BIML(?) 的建议。
  • @BenjaminJedd 如果您熟悉 BIML,则更容易实现此目标
  • 我的同事和我刚刚尝试使用 BIML(必须安装和查找补丁真的很糟糕),它似乎是一次性运行,除非我学习如何编写 c# 脚本来动态做我最初想做的事情,但使用 BIML。我需要一个连续运行的 /single/ 包,它一次为每个表提取一个数据,然后通过 table_name 将其动态加载到数据库中。 C# 脚本应该加载单独的包并更新元数据,因为 VS 无法自行执行此操作。虽然易于使用且引人入胜,但 BIML 似乎并不是解决此问题的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多