【发布时间】:2018-06-15 08:18:08
【问题描述】:
我有一个 SSIS 包,可以将数据从 Microsoft Access 复制到 SQL Server。两组表几乎相同。
背景:不出所料,我们的表架构随着我们产品的开发而增长。因此,我们一直需要使用新列更新 SSIS 包。这是一项非常枯燥的任务,因此我尝试在 C# 中以编程方式创建 SSIS 包。进展顺利,但我想让这个过程更简单。
问题: 包生成过程要求源 (Access) 和目标 (SQL Server) 在 C# 运行时存在。这不适用于我们当前的流程。因此,我想:
- 以编程方式提供表和列(SQL 和 Access 表是从 XML 元数据生成的,因此我们可以从相同的元数据向 SSIS 提供表和列)
- 在加载包的时候,运行一些C#来修改包,即ReinitializeMetaData等
我非常喜欢这两种解决方案中的第一种。但是我不知道如何使它们中的任何一个起作用。
更多详情:我一直在使用以下 SSIS 代码(来自 Microsoft 的示例)。我想我想要一些无需执行 AcquireConnections 或 ReinitializeMetaData 即可运行的东西——我想自己提供元数据。显然,我提供的内容必须与验证和运行包时实际存在的内容完全匹配。
public IDTSComponentMetaData100 AddDestAdapter(IDTSPipeline100 pipeline, ConnectionManager destConnMgr, out IDTSDesigntimeComponent100 destDesignTimeComp)
{
IDTSComponentMetaData100 destComp = pipeline.ComponentMetaDataCollection.New();
destComp.ComponentClassID = OLEDB_DEST_GUID;
destComp.ValidateExternalMetadata = true;
destDesignTimeComp = destComp.Instantiate();
destDesignTimeComp.ProvideComponentProperties();
destComp.Name = "OleDB Destination - Sql Server";
destDesignTimeComp.SetComponentProperty("AccessMode", 0);
destDesignTimeComp.SetComponentProperty("OpenRowset", quotedTableName);
// set connection
destComp.RuntimeConnectionCollection[0].ConnectionManager = DtsConvert.GetExtendedInterface(destConnMgr);
destComp.RuntimeConnectionCollection[0].ConnectionManagerID = destConnMgr.ID;
// get metadata
destDesignTimeComp.AcquireConnections(null);
destDesignTimeComp.ReinitializeMetaData();
destDesignTimeComp.ReleaseConnections();
extCols = destComp.InputCollection[0].ExternalMetadataColumnCollection;
return destComp;
}
public void AddPathsAndConnectColumns()
{
IDTSOutput100 srcOutput = srcComp.OutputCollection[0];
IDTSOutputColumnCollection100 srcOutputCols = srcOutput.OutputColumnCollection;
IDTSInput100 destInput = destComp.InputCollection[0];
IDTSInputColumnCollection100 destInputCols = destInput.InputColumnCollection;
IDTSExternalMetadataColumnCollection100 destExtCols = destInput.ExternalMetadataColumnCollection;
Hashtable destColtable = new Hashtable(destExtCols.Count);
foreach (IDTSExternalMetadataColumn100 extCol in destExtCols)
{
destColtable.Add(extCol.Name, extCol);
}
// colConvertTable stores a pair of columns which need a type conversion
// colConnectTable stores a pair of columns which dont need a type conversion and can be connected directly.
Hashtable colConvertTable = new Hashtable(srcOutputCols.Count);
Hashtable colConnectTable = new Hashtable(srcOutputCols.Count);
foreach (IDTSOutputColumn100 outputCol in srcOutputCols)
{
// Get the column name to look for in the destination.
// Match column by name if match table is not used.
String colNameToLookfor = outputCol.Name;
IDTSExternalMetadataColumn100 extCol = (String.IsNullOrEmpty(colNameToLookfor)) ? null : (IDTSExternalMetadataColumn100)destColtable[colNameToLookfor];
// Does the destination column exist?
if (extCol != null)
{
colConnectTable.Add(outputCol.ID, extCol);
}
}
// Convert transform not needed. Connect src and destination directly.
pipeline.PathCollection.New().AttachPathAndPropagateNotifications(srcOutput, destInput);
IDTSVirtualInput100 destVirInput = destInput.GetVirtualInput();
foreach (object key in colConnectTable.Keys)
{
int colID = (int)key;
IDTSExternalMetadataColumn100 extCol = (IDTSExternalMetadataColumn100)colConnectTable[key];
// Create an input column from an output col of previous component.
destVirInput.SetUsageType(colID, DTSUsageType.UT_READONLY);
IDTSInputColumn100 inputCol = destInputCols.GetInputColumnByLineageID(colID);
if (inputCol != null)
{
// map the input column with an external metadata column
destDesignTimeComp.MapInputColumn(destInput.ID, inputCol.ID, extCol.ID);
}
}
}
可能的探索路线:
- This MSDN thread 有人有同样的问题(虽然没有具体的解决方案)
- 根据对 BIML 的一些调查,似乎 BIML struggles with the same issues(OfflineSchema 似乎可以工作,虽然我有点担心,因为我在 Internet 上找不到一个示例)。李>
【问题讨论】:
-
也许您需要在 SSIS 之外构建自定义流程(似乎与 SSIS 函数不匹配,因为您的流程非常动态)。
-
一定要调查 Biml。使用要提取的表(甚至可能是列)的元数据框架,开发将输出所需 SSIS 包的 Biml 脚本几乎是微不足道的。如果您需要在 SSIS 创建中包含更复杂的逻辑,您可以使用
C#作为 Biml 中的 sn-ps 或作为引用文件来调用函数。