使用脚本任务创建 ADO NET (ODBC) 数据流源
Posted
技术标签:
【中文标题】使用脚本任务创建 ADO NET (ODBC) 数据流源【英文标题】:Using Script Task to create ADO NET (ODBC) Data Flow Source 【发布时间】:2012-09-14 20:34:39 【问题描述】:我需要一些有关动态创建包的 SSIS 脚本任务 (SQL 2008 R2) 的帮助。我正在改进一个包,它将数据从 Sage Timberline(现在更名为 Sage 300)Pervasive SQL 环境复制到 SQL Server 数据仓库。我可以创建一个包来打开与 Timberline 的连接并将数据复制到 SQL Server 中的表中。问题是,对于林中的每个公司和 SQL 中的每个表,我都需要创建一个单独的数据流任务。鉴于 Timberline 公司的三个文件夹和每个文件夹中的表格数量,这将花费大量时间来创建,并且维护和故障排除也很麻烦。
我正在尝试创建一个包,该包使用 Foreach 循环来创建一个包,该包创建一个 ADO/ODBC 源 (Timberline)、一个 OLE 目标 (SQL) 并动态处理列映射。我发现代码here 几乎可以满足我的需要。
我测试了这段代码,它在使用 OLE SQL 源和目标时效果很好。使这个脚本工作的原因是它动态地处理列映射。因此,如果您将其放入 100 个左右表的 Foreach 循环中,每个循环都可以动态创建数据流并映射列,然后执行新包。
我的问题是我只能使用 ODBC 连接到 Timberline。因此,我需要修改脚本以使用 ADO NET (ODBC) 而不是 OLE 创建源连接。我在试图弄清楚这一点时遇到了很多麻烦。有人可以帮我解决这个问题吗?
这是我首先尝试的其他几件事,除了这种方法:
解决方案:将链接服务器设置到 Timberline Pervasive SQL 问题:SQL 服务器是 64 位的,而 Timberline 驱动程序是 32 位的。使用链接服务器会返回架构不匹配错误。我打电话给 Sage,他们说他们没有发布 64 位驱动器的计划。
解决方案:使用 SQL 传输任务之一 问题:仅适用于 SQL 数据库。此来源是 Pervasive SQL 数据库
解决方案:使用“INSERT ... INTO ...”类型的脚本 问题:这需要一个链接服务器。看上面的问题
这是original VB .NET code 我需要帮助的部分:
'To Create a package named [Sample Package]
Dim package As New Package()
package.Name = "Sample Package"
package.PackageType = DTSPackageType.DTSDesigner100
package.VersionBuild = 1
'To add Connection Manager to the package
'For source database (OLTP)
Dim OLTP As ConnectionManager = package.Connections.Add("OLEDB")
OLTP.ConnectionString = "Data Source=.;Initial Catalog=OLTP;Provider=SQLNCLI10;Integrated Security=SSPI;Auto Translate=False;"
OLTP.Name = "LocalHost.OLTP"
'To add Load Employee Dim to the package [Data Flow Task]
Dim dataFlowTaskHost As TaskHost = DirectCast(package.Executables.Add("SSIS.Pipeline.2"), TaskHost)
dataFlowTaskHost.Name = "Load Employee Dim"
dataFlowTaskHost.FailPackageOnFailure = True
dataFlowTaskHost.FailParentOnFailure = True
dataFlowTaskHost.DelayValidation = False
dataFlowTaskHost.Description = "Data Flow Task"
'-----------Data Flow Inner component starts----------------
Dim dataFlowTask As MainPipe = TryCast(dataFlowTaskHost.InnerObject, MainPipe)
' Source OLE DB connection manager to the package.
Dim SconMgr As ConnectionManager = package.Connections("LocalHost.OLTP")
' Create and configure an OLE DB source component.
Dim source As IDTSComponentMetaData100 = dataFlowTask.ComponentMetaDataCollection.[New]()
source.ComponentClassID = "DTSAdapter.OLEDBSource.2"
' Create the design-time instance of the source.
Dim srcDesignTime As CManagedComponentWrapper = source.Instantiate()
' The ProvideComponentProperties method creates a default output.
srcDesignTime.ProvideComponentProperties()
source.Name = "Employee Dim from OLTP"
' Assign the connection manager.
source.RuntimeConnectionCollection(0).ConnectionManagerID = SconMgr.ID
source.RuntimeConnectionCollection(0).ConnectionManager = DtsConvert.GetExtendedInterface(SconMgr)
' Set the custom properties of the source.
srcDesignTime.SetComponentProperty("AccessMode", 0)
' Mode 0 : OpenRowset / Table - View
srcDesignTime.SetComponentProperty("OpenRowset", "[dbo].[Employee_Dim]")
' Connect to the data source, and then update the metadata for the source.
srcDesignTime.AcquireConnections(Nothing)
srcDesignTime.ReinitializeMetaData()
srcDesignTime.ReleaseConnections()
提前致谢!
【问题讨论】:
【参考方案1】:如果您需要在源和目标之间进行派生列转换,则需要这里的 C# 代码...
http://bifuture.blogspot.com/2011/01/ssis-adding-derived-column-to-ssis.html
为了使源和目标连接正常工作,这里有一些秘诀可以让 COM 和 .Net 之间正常工作... http://blogs.msdn.com/b/mattm/archive/2008/12/30/api-sample-ado-net-source.aspx 有一个类似的页面也显示了如何处理 OleDB 连接。
创建源表很容易。应使用 GetSchema("MetaDataCollections") 检索可访问的可用 ODBC 元数据集合。这将返回可用于该特定 ODBC 驱动程序的可用架构集合的列表。 接下来,您将希望查看从 GetSchema("DataTypes") 返回的数据类型,以便您可以正确解释从 GetSchema("Columns") 检索到的每一列的数据类型,以使您的 SQL Server 创建表脚本(我'我假设你已经完成了)。 为了至少确定哪些表具有主键,您需要遍历从 GetSchema("Tables") 返回的每个表,以便使用 GetSchema("Indexes")。有一个错误要求您一次查询一个表的索引。这很容易用谷歌搜索 - 创建一个字符串数组作为第三个参数传入:GetSchema("Indexes", tblName, resultArray[])
我所做的是将 Tables 和 Columns 集合放入我的父 SSIS 包中的对象变量中。因为 Timberline 非常快(不是),所以将所有列拉下来并在本地过滤它们似乎更有效......如果需要,我这样做是为了在 SQL Server 中创建表。
完成后,再次使用 Tables 的本地副本在“设计模式”的脚本任务中操作 SSIS 包(更改源和目标目标表,并重做列映射),并执行 now-in -memory SSIS 包。
对我来说,花了一段时间才弄清楚。以上两个 URL 都是必需的。我找到并将 .Net 2.0 Dts.PipelineWrap 和 Dts.RuntimeWrap .dll 复制到 Microsoft.Net\FrameworkV2.0xxxxx 文件夹,然后在每个想要使用它们的脚本任务中引用这些,然后设置我的“使用 DtsPW = Microsoft.SqlServer .Dts.Pipeline.Wrapper”等
值得注意的是,由于 Timberline 是 32 位 ODBC,我认为有必要构建 SSIS 包以使用“X86”,并将脚本任务定位为使用 .Net 2.0 框架。
我使用派生列代码是因为我需要将多个 Timberline 数据库复制到一个 SQL Server 数据库中。派生列将“CompanyID”值添加到 SQL Server 的输出管道。
最后,根据目标附加到的管道,将目标的虚拟输入列映射到其外部元数据列:
foreach (DtsPW.IDTSVirtualInputColumn100 vColumn in destVirtInput.VirtualInputColumnCollection)
var vCol = destInst.SetUsageType(destInput.ID, destVirtInput, vColumn.LineageID, DtsPW.DTSUsageType.UT_READWRITE);
destInst.MapInputColumn(destInput.ID, vCol.ID, destInput.ExternalMetadataColumnCollection[vColumn.Name].ID);
无论如何,该代码在 bifuture.blogspot.com 页面的上下文中会更有意义。
EzApi 库也可以帮助解决这个问题,但它的 AdoNet 连接源被编码为虚拟类,因此您需要实现特定的类才能使用。我的 C# 功夫在我有的时候还不够强大...
此外,CozyRoc 还销售一个带有自定义 SSIS 控件(数据流源和目标控件...)的工具集,看起来它也可以在输入到输出列映射时执行此操作。
我的包现在似乎工作得很好......哦,还有一个,我没有运气尝试使用无 DSN 的 ODBC 连接到 Timberline,只是:Dsn=dsnname;Uid=user;Pwd=pwd;
在 64 位土地上运行的 SSIS 包在 64 位操作系统上看不到 32 位 DSN,看来……至少,它对我不起作用(win7-64、32 位文本 ODBC DSN) .
【讨论】:
以上是关于使用脚本任务创建 ADO NET (ODBC) 数据流源的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 EF Core 或 LinqToDb EF Core Tools 或 ADO.NET 运行任何存储过程创建脚本