| xiaoxinlucky | | 2008-1-8 08:06 |
|
Project REAL:在SQL Server Integration Services中开发自定义组件
[b]应用于[/b]
SQL Server 2005 Beta 2和IDW 9 Community Preview
[b]摘要[/b]
Project Real第一个阶段,包括为一个大型电子零售商的现有SQL Server 2000 DTS包到SQL Server 2005 Integration Services (SSIS)的转移。数据仓库的信息的源是TLog文件,它包含了在存储中从销售点收款机产生的数据。TLog以压缩十进制格式存储文件。为了提取并将这些数据转换到一个适合加载到关系型数据仓库表中的格式,需要打开并解析这些文件。这样,就需要扩展SSIS对象模型,实现自定义管道组件,来读取和转换这些数据。这篇文章讨论了当实现自定义管道组件来从TLog中提取和解析数据时,我们学到了什么。
[b]版权说明[/b]
这是一份初版文件,可能会于本软件产品正式发行之前依实况进行必要的修订。
本文件中所包含的信息代表 Microsoft Corporation 于发行日前针对该问题的观点。由于 Microsoft 必须反应市场条件的变更,因此不应解释为 Microsoft 的承诺。在发行日之后,Microsoft 不保证文件中任何信息的正确性。
此白皮书仅供参考使用。MICROSOFT 对于本文件中各项信息,不作任何明示、暗示或法定的保证。
使用者必须遵守所有适用的版权法律规定。在不影响版权各项权利的情况下,若无 Microsoft Corporation 的明确书面许可,本文件中的任何部份均不得因任何目的,以各种可能的形式或方式 (电子、机械、影印、录制或其它方式) 进行复制、储存或导入至检索系统或传送。
本文件中可能述及 Microsoft 的专利、专利应用程序、商标、版权或其它智能财产权。除非取得 Microsoft 明确书面授权声明,否则本文件并未授予这些专利、商标、版权或其它智能财产的授权。
除非另有说明,本文档中用作示例的公司、组织、产品、域名、电子邮件地址、徽标、人员、地点和事件均是虚构的,并不是有意或者不应推断为与任何真实的公司、组织、产品、域名、电子邮件地址、徽标、人员、地点或事件有关联。 2005 Microsoft Corporation。保留所有权利。Microsoft,Visual C# .NET,和Visual Studio是 Microsoft Corporation 在美国和/或其它国家/地区的注册商标或商标。本文档中提到的真实公司和产品的名称均是各自所有者的商标。
目录
简介: Project REAL
第1阶段的实现
核心ETL处理
为什么用自定义组件?
加载TLog数据到数据仓库中的设计
SSIS对象模型和管道组件
自定义组件的实现
自定义源适配器
设计一个源适配器
运行时
自定义TLog转换
设计一个异步转换组件
异步组件的运行时方法
部署
为程序集创建强名称
编译任务
将任务移动到适当的目录中
添加任务到SSIS工具箱中
使用自定义组件创建包
调试
收获
结论
[b]简介: Project REAL[/b]
Project REAL是一项为创建基于Microsoft® SQL Server™ 2005的商业智能应用程序寻找最佳实践的工作,它基于实际客户场景创建参考实现。这意味着客户数据在内部,并用来解决在部署时客户面临的相同的问题。这些问题包括:
• 架构的设计。
• 数据提取,转换和加载(ETL)过程的实现。
• 生产系统的尺寸。
• 系统的管理和维护。
通过处理实际的部署场景,我们完全理解了如何使用这些工具。我们的目标是,在一个大型公司的实际部署过程中,尝试处理他们可能面临的所有问题。本文集中于处理Project REAL中的第1阶段的ETL部分,以及开发自定义组件的经验和技巧。
Project REAL使用来自两个Microsoft商业智能客户的数据。项目的第1阶段仿效一个大型电子零售商,他们将销售和商品目录的数据保存在SQL Server 2000数据仓库中。SQL Server 2000的Data Transformation Services (DTS)用来管理数据存入关系型数据库,并从关系型数据库中传递到SQL Server 2000 Analysis ServicesCube中,用来报表和交互查询。这个客户在他们的数据库中存储了将近200GB的数据。随后,所有这些数据都被处理到Analysis ServicesCube中。第1阶段的实现主要集中于,当执行一个到SQL Server 2005的迁移时,现有的SQL Server 2000客户可能关注的问题。我们的结果主要表示现有的功能的迁移,在合适的地方使用一些新功能。在ETL的范围内,要基于现有的SQL Server 2000 DTS包,并用SQL Server 2005 Integration Services (SSIS)来创建包,需要大量的工作。
注意:SQL Server Integration Services (SSIS)是原来的DTS的新名字。这个产品在Beta 2以后就被重命名。因此新的SSIS的许多场景在本文中仍然用原来的名字。
Project REAL的第2阶段基于一个来自不同客户的更大的数据集,并将使用更多的SQL Server 2005中的新功能。这是因为第2阶段主要是一个SQL Server 2005 解决方案的新的实现。查阅更多关于Project REAL的白皮书,在Project REAL Web site ([url]http://www.microsoft.com/sql/bi/ProjectReal/)[/url]。
Project REAL是由Microsoft Corporation,Unisys,EMC,Scalability Experts,Panorama,Proclarity,和Intellinet合作完成的。本文中描述的工作是由Scalability Experts和Microsoft Corporation完成的。
[b]第1阶段的实现[/b]
第1阶段的客户有两个主要的流入数据仓库的信息来源。它们是:
• TLog文件,它是由销售点(POS)的收款机的存储输出的。(不要和SQL Server事务日志文件相混淆)
• 从JDA系统中提取出的直接文件(一个封装的零售软件应用程序),用来管理业务。
全部的数据流,由SQL Server 2000 DTS管理,如图1所示。
[img]http://298853.blog.51cto.com/album/288853/119977923852.jpg[/img]
图 1: 第1阶段的客户数据流
[b]核心ETL处理[/b]
要加载客户的数据仓库所执行的核心ETL处理如下:
1. TLog文件来自销售点(POS)取款机,并以一个特别的高压缩的格式存储,所以在这些文件加载到数据库之前,先要将它们解码。客户的应用程序基于预先定义的标准,压缩这些POS事务为压缩十进制格式。
2. 应用程序以一个数值序列为每个文件命名。它依照存储数将名字存储在适当的目录下。这种命名习惯对于支持需要使用很长时间的文件来说是有必要的,同时对于支持每天要写多个文件的情况来说也很有用。
3. 在数据被加载到数据库之前,客户用Perl脚本经TLog二进制文件解析到多个文本文件中。这个脚本使用一个预定义的模版拆开数据。然后,这个脚本根据一个格式说明文件(.ini)中定义的一些规则,来解压数据。
4. 来自脚本的输出存储在直接文件中。然后,直接文件被一个DTS包读取,并且数据被加载到数据库中。所以,在数据能被处理前需要附加两步操作-一个是解析数据,一个是加载直接文件输出。
为了在SSIS中利用新功能并改善性能,我们决定在SQL Server 2000中重新设计现有的DTS包。这将允许我们通过对现有方法的一个简单迁移,来衡量性能的提升。作为这个迁移的一部分,Scalability Experts创建了一个TLog解析器,它在SSIS管道中运行。它有效的消除了一个代价很大的步骤并帮助减少处理TLog文件的存储需求。每个包含着压缩数据的TLog文件,通过使用一个custom source component,直接读取到SSIS管道中,并使用一个custom transformation component进行解析。下个小节详述了改变架构的优势。
注意:这篇文章描述了,我们从写TLog解析器的实现所需要的自定义组件中学到的东西。在Project REAL的第1阶段,关于SSIS的高级课程,查看SQL Server 2005 Integration Services: Lessons from Project REAL。
因此我们想要完全演习整个系统,客户必须提供数据仓库的初始状态,以及销售和库存系统的三个月以来的增量更新。这允许我们模拟一个完全的处理周期,包括关系型和OLAP数据库中的自动化分区管理。
本文除了描述ETL相关的工作以外,团队还在Project REAL中执行了各种其他的工作,包括:
• 从SQL Server 2000中将关系型数据迁移到SQL Server 2005中,并精确保留架构。
• 伪装客户数据来保护机密消息。
• 将Analysis Services 2000数据库迁移到SQL Server 2005 Analysis Services (SSAS)中。
• 使用客户的选择的前端工具 (Microsoft Excel和Proclarity)验证客户端的连通性。
• 使用SQL Server 2005 Reporting Services (SSRS),根据新的Cube创建示例报表。
• 在SSAS中完全实现一个新的Inventory Cube。由于数据的庞大,客户在处理度量值时显然遇到了困难。因此,客户停止了在这个方面的工作。Analysis Services 2005中的新功能可以使用额外的度量,即使在数据量非常大的情况下。
这篇文章的剩余部分,说明了在处理移动客户的ETL处理到SQL Server 2005 Integration Services的过程中,所学到的东西。本文还强调了很多最佳实践。
[b]为什么用自定义组件?[/b]
对于销售和分发应用程序,为了节省空间,通常会将未经处理的事务压缩到文件中以节省空间。在Project REAL中,就像核心ETL处理中讨论过的那样,处理的数据是由销售点(POS)应用程序所产生的压缩TLog文件组成的。想要知道为什么要实现自定义组件,首先要理解为什么要加载POS数据。POS数据存储在压缩十进制文件中,如图2所示。
[img]http://298853.blog.51cto.com/album/288853/119977924216.jpg[/img]
图 2: 示例TLog 压缩文件
这个文件可以使用压缩时的模版来进行解压缩。这个模版是一个字符序列,它定义了值的顺序和类型,这个值用来压缩到二进制文件中。下面是一部分示例模版文件,用来实现过程中解压和压缩二进制文件。
"00" => ["H2","H4","H5","H6","H4","H8"]
"01" => ["H2","A12","H4”]
"03" => ["H2","A5","A12"]
其中
H: 一个十六进制串(高四位优先)。
A: 一个ASCII字符串。
数字: 包含特定编码的字节数。
每行压缩数据的开头的两个十六进制的值,代表了模版的行类型。即,这些开头的两个数字为行中剩下的部分定义了模版。在示例模版中,定义了三个行类型。他们是"00", "01", 和"03"。对于以"03"开头的行来说,前两个字节将是一个十六进制的值,跟着是5字节的ASCII字符,跟着是12字节的ASCII字符。
使用这个模版,文件被解压。
在文件被解压后,数据需要被进一步解析,来提取关于事务的详细信息。解析文件将会是一个挑战,因为有多个行限定符,并且每一行都是一个单独的事务,其中包含不等数量的列。因而,转换文件所需要提供的字段类型,在一个说明文件中定义。下面是一个用来转换TLog文件的示例说明文件。
[00] Filename="Header Item" DelimiterCharacter="," Outputs="%store,0-2-2,0-1-0,0-2,----------------------------
[03] Filename="Sales Receipt"
DelimiterCharacter="," Outputs="%store,3-0,3-1,………………………………..
被解开的事务的前两个十六进制值定义了事务信息的类型。这可能是支付信息,比如折扣信息,也可能是用户信息。例如,在示例模版中,事务类型”00”定义了事务是一个Header。基于事务的类型,说明文件包含了解析数据和提取有用信息所必须的值和方法。
客户用Perl脚本来处理这些信息。可扩展的SSIS对象模型和.NET语言的支持,给我们提供了用SSIS管道本身的自定义组件,来实现解压,解析,和提取的ETL过程的机会。它将帮助我们提高性能和可管理性。如果我们用现有的Perl脚本在SSIS管道外面解析TLog文件,那将不会带来这些优势。
这个过程的实现,将会带来巨大的优势,如下:
• 有效的、强壮的ETL,因为从压缩十进制TLog文件中提取数据,将包含在相同的SSIS管道中,而不是一个单独的手动处理。TLog数据可能在这个进程中被提取,它能够使用内建的SSIS转换任务做进一步的处理,并且可以在同一个管道中,被存储到任何目标中(比如SQL Server或直接文件中)。
• 更加容易管理,因为Perl解析器被SSIS管道中的自定义组件代替。因此,没有必要实现或执行SSIS管道以外附加的应用程序。同样,在将它们加载到数据仓库的关系型表中之前,也不需要附加的存储来保存中间的解析文件。
• 更快的ETL处理,因为在每种转换之间,不需要将数据写到磁盘上的一个中间格式或从上面读,也就不会招致附加的I/O操作。
• 数据流更加灵活和可控制,因为终端用户决定具体将要被提取的输出(子表)。
TLog文件包含大约24种不同的输出信息,比如Rebates,User Description,Discounts,和Header Information。显然,Perl解析器所有这些子表到不同的文件中(每个TLog文件有24个文件),不论数据仓库应用程序是否需要。设计在数据被转换到下游目标之前,允许用户挑选需要的输出。因此,不必要的输出流被避免,致使提高了性能和可管理性。
• 容易修改,因为自定义组件是用托管代码,比如Visual C#® .NET,实现的,它能够比低级语言,像Perl,提供更好的调试和更容易修改。
另外,设计提供了模版文件来解压文件,并且提供了说明来解析数据,它们在自定义组件中作为单独的输入出现。因此,对格式说明的任何更改将很容易实现,并且不会修改自定义组件本身。
因为实现自定义组件的成本和性能上的收益,远远超过了消耗的成本,我们决定继续这个项目。因为这个过程会控制数据流从压缩十进制文件到数据仓库中,所以决定在数据流中用管道组建来实现这个任务。为了更好管理和实现模块化编程,解压压缩十进制文件和解析文件以提取数据作为分别的组件实现。下面的两个自定义组件被实现。
• source adapter,将解压压缩文件并将它转换到相关的编码。
• custom transformation,将基于一个给定的说明解析文件。
[b]加载TLog数据到数据仓库中的设计[/b]
本小节讨论了开发提取和转换来源于不同的存储的TLog文件中存储的销售点数据的设计。
每个存储中的TLog数据文件被组织在一个目录中。这些目录依据存储数来命名。在每个目录中,TLog文件按照数字的次序被安排。一个附加的Start文件被包含在目录中,它包含了最后一个处理的文件的名称。要访问一个TLog文件,首先要通过循环存储目录的集合,访问特定的存储目录。然后,要循环访问每一个TLog存储目录,来提取一个特定的TLog文件。在它最终被进一步转换到SQL Server 数据仓库适合存储的格式前,这个TLog文件必须被解压,并被解析。
在TLog文件中的数据被处理之前,必须要能连接到这些文件。要连接源文件:1)循环访问存储目录,并且2)对每一个目录,循环访问TLog文件。在SSIS中,这些处理通常是通过不同的控制流任务实现的。
只要连接到了TLog文件,就可以解压数据了。被解压的数据还要基于定义好的说明,经过近一步解析,来提取有用的信息。这些都完成后,就可应用附加的转换,并将数据加载到目标中。通常,没有内建的任务可以用来解压和解析压缩的十进制文件。因此,我们创建自定义组件,并基于SSIS管道中定义的说明,来解压和解析TLog文件。这样获得了更好的可管理性,两个自定义组件被实现-一个用来读取和解压文件,另一个用来解析文件。
要实现上面的设计,需要用到下面的控制流和数据流任务。
[b]控制流任务[/b]
下面的控制流任务用来访问源TLog文件。
1. 一个自定义的For Each Directory容器,它循环访问不同的包含TLog文件的存储目录。
注意:一个自定义的For Each Directory任务包含在September CTP的示例SSIS应用程序中。(文件路径:<installedsamplesdirectory>\Integration Services\Programming Samples\Control Flow\ForEachDirectory Sample directory)
2. 对于每个提取的目录,For Each File内建的容器用来在每个目录中循环访问TLog文件。
3. 每个TLog文件的文件路径被提取出来,并在数据流源适配器中,被动态的设定为源表。
4. 一个数据流任务读取,解压,并解析数据,并且加载它到数据仓库所需要的关系型目标表中。
[b]数据流任务[/b]
下面的数据流任务用来提取,转换,并加载数据。
1. 一个自定义的源适配器被实现,用来读取压缩十进制TLog文件,并根据提供的模版解压它到相应的编码。
2. 一个自定义转换任务用来使用.ini输入文件中提供的说明转换数据。
3. 在需要时完成附加的转换。
4. SQL Server Destination Adapter,是内建的目标组件,用来加载数据到SQL Server中。
[b]SSIS对象模型和管道组件[/b]
理解新的SSIS对象模型是讨论实现自定义组件的先决条件。本小节讨论了SSIS对象模型和它的各种组件。
在SSIS对象模型中,主要的运行时组件是task和container。数据的管理和处理是通过单独的task来控制的。如图3所示,这些task被集中到container中。Container在包中提供了循环和分支的控制流。DTS运行时引擎执行task和container的顺序通过优先的约束来定义。这个优先约束未task和container的执行定义了条件。
[img]http://298853.blog.51cto.com/album/288853/119977924432.jpg[/img]
图 3: SSIS对象模型
数据流任务从不同的源提取数据,然后转换,净化,并修改数据,并将它存到适当的目标中。您可以把一个数据流任务想象成一个有向无环图,把源适配器、转换、和目标适配器想象成图的结点。每个组件通过有向路径连接,它决定了数据流。
SSIS 2005相比于DTS 2000做出的一个巨大的进步是它的性能。对于数据流任务,组件之间的多数数据流都是由in-memory数据存储(缓冲器)来控制的。数据流引擎创建执行计划并为每个组件定义所需的缓冲器。当缓冲器满了以后,数据将会被推到下游组件。数据流在内存中控制,而不是通过代价较高的I/O操作,结果得到了更快的数据传输和转换速度。
在这个项目中的一个挑战是扩展对象模型,来实现自定义组件。但是,整个底层的SSIS对象模型已经被重新建造过了,并具备课扩展性。新的SSIS对象模型提供了对核心Microsoft .NET Framework的支持。它使得Microsoft Visual Studio®为设计和调试提供了一个强大的集成开发环境(IDE)。
要扩展SSIS对象模型,开发人员需要考虑对SSIS包的两个级别的开发。SSIS体系结构分别处理设计和运行时的包。
注意:在本文中,提到的实现自定义组件的源代码的人叫作开发人员,在Business Intelligence Development Studio中使用这些自定义组件创建SSIS包的人叫作用户或终端用户。
数据流任务中的每个组件以一个图形化的方式用数据路径连接,该路径控制数据流,如图4所示。每个上游组件提取和处理数据,并将他们推到下游的组件中。每个组件由二个重要的子元素组成:用户界面(UI)和元数据。
元数据在设计中定义了组件的角色。元数据由组件信息(如自定义属性),输入和输出集合,和每个输入和输出集合中的列组成。数据通过in-memory存储(管道缓冲器)在组件间被传递。如图4所示。
[img]http://298853.blog.51cto.com/album/288853/119977924883.jpg[/img]
图4:数据流任务
在设计状态下用户选择数据流组件和适当的数据路径。用户在这种级别下允许改变每个组件的元数据。例如:一个用户可能为不同组件的定义了自定义的属性,并决定了数据流。用户也可以为每个组件以及他们相关的列集合决定输入和输出的数量。另外,用户可以从每个输出到下一个下游组件指定数据流。在设计级别下,组件必须能够对这些元数据的改变做出响应。例如:组件可能允许或不允许添加和删除输入和输出。所以组件应当足够灵活,以适应这些改变。
在运行时阶段,数据流组件被执行。在这个阶段,数据流引擎为数据流定义了执行计划,然后创建和分配缓冲器。它分配了工作线程,并且以用户在图形格式下安排的顺序调用不同的组件,如源,转换,和目标。另外,数据流引擎处理错误和任务的完成。
要创建一个自定义的数据流组件,您需要继承PipelineComponent基类。PipelineComponent实现了IDTSDesigntimeComponent90接口,定义了数据流任务的设计时的行为。要定义运行时的行为,必须定义IDTSRuntimeComponent90接口。两个接口中的方法和事件,您可以在您的组件中进行覆盖。要实现和覆盖数据流组件的虚方法,将下列引用添加到您的项目中。
• 程序集: microsoft.sqlserver.dtspipelinewrap
默认路径: %program files%\microsoft sql server\90\sdk\assemblies\microsoft.sqlserver.dtspipelinewrap.dll
• 程序集: microsoft.sqlserver.dtsruntimewrap
默认路径: %program files%\microsoft sql server\90\sdk\assemblies\microsoft.sqlserver.dtsruntimewrap.dll
• 程序集: microsoft.sqlserver.manageddts
默认路径: %program files%\microsoft sql server\90\sdk\assemblies\microsoft.sqlserver.manageddts.dll
• 程序集: microsoft.sqlserver.pipelinehost
默认路径: %program files%\microsoft sql server\90\sdk\assemblies\microsoft.sqlserver.pipelinehost.dll
在包执行之前,管道组建处于设计状态。在这个状态,元数据可以不断的改变。在这个状态,用户可以通过添加或删除组件,以及设定数据流路径和组件的元数据来决定布局。Business Intelligence Development Studio 中的SSIS设计器通过设计时的IDTSDesigntimeComponent90接口与组件进行交互。在设计状态下,用户选择的每个节点或组件都包含一个Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSComponentMetaData90接口,和一个到相应的用户组件的设计时接口的引用。数据从上游组件到下游组件的移动是通过数据路径来定义的,这个数据路径是通过Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSPath90对象的集合来定义的,它定义了组件之间的数据的移动。
运行时的方法是通过工作线程执行的,该线程也是由数据流任务管理的。工作线程调用运行时的IDTSRuntimeComponent90接口执行运行时方法。
在运行时,数据流任务为数据流组件的执行生成了一个执行计划。该执行计划为组件的每个序列生成了一棵执行树,该序列从一个源或从一个异步组件开始,到目标或另一个异步组件结束。根据查询计划,为每个组件序列的输出列的集合创建缓冲器。这个缓冲器包含了所有组件的列集合,直到遇到一个异步组件或目标组件为止。如果遇到了一个异步组件,那么将会创建一个包含下个组件序列的缓冲器。因此,这个缓冲器将会在一个特殊的执行树中,为一个组件序列所重用。
它通过允许多个组件重用相同的缓冲器对象来提供优化,这样减少了缓冲器的内存复制的数量,因此提高了效率。
为了实现这个功能,引擎在运行时执行计划中维护一个恒定的缓冲器定义。当上游的组件创建管道缓冲器时,它为即将被创建的下游组件的列分配空间。因为上游组件只对为他们的列保留的空间进行写操作,所以在运行时,将会在组件级别上,出现比在设计时用户选择的更多的列。
运行时引擎分配管道缓冲器。输出行被存储在缓冲器中,直到它满了为止。那时数据将被推入下一个组件。缓冲器单元由于审核的目的,保存每一列的值。这些列通过唯一的标识符提供。这些标识符在缓冲器中映射列索引。在执行时,列通过使用像FindColumnbyLineageID的方法来定位。
初始的的程序设计包括继承PipelineComponent基类。您需要定义命名空间,并指定类的DtsPipelineComponent属性。对于自定义的源适配器,通过继承PipelineComponent类来定义命名空间和类,如下所示:
using System;
using Microsoft.SqlServer.Dts.Pipeline;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using Microsoft.SqlServer.Dts.Runtime;
#endregion
namespace TLogSourceComponent
{ #region ClassAttribute
[
DtsPipelineComponent
(
DisplayName = "TLOG Source",
ComponentType = ComponentType.SourceAdapter,
IconResource = "TLogSourceComponent.TLogSource.ico",
Description = "This source component unpacks the packed decimal fields in a POS TLOG and returns a single column as record/string/substring structure."
)
]
#endregion
public class TLGSrc : PipelineComponent
{
\\ write the code here
}
} |
| xiaoxinlucky | | 2008-1-8 08:12 |
|
[b]自定义组件的实现[/b]
通过使用一个.NET Framework语言,对象模型可以被扩展来创建自定义任务。这个特别的解决方案是通过C#托管代码来实现的。项目在Visual Studio 2005 开发环境中实现。剩下的实现和API的使用,用C#来解释。
自定义组件作文单独的项目被创建,能够得到更好的可管理性。每个项目被编译并生成需要的程序集(.dll)文件。这些程序集可以用宿主语言程序共享,比如Business Intelligence Development Studio。
本节剩余的部分讨论了自定义源适配器和自定义转换的实现细节。
[b]自定义源适配器[/b]
源适配器允许用户从不同的数据源中提取数据。源适配器可以含有许多数据和错误输出。因为源适配器是数据流任务中的第一个组件,它不需要包含任何输入。因为源适配器不包含输入,所以它直接连接到数据源并提取所需的数据。
输出可以包含一个定义类型的一个或多个列,用来在数据流管道中将数据转移到下游。错误输出列也是一样的。但是,在实现中,开发人员可以通过重载不同的方法,显示的拒绝用户添加或删除列或输出的能力,比如DeleteOuputColumn()和InsertOutputColumn()方法。如果实现允许删除列,那么在设计时用户可以选择不同的需要的输出及相关的列。
对于TLog源适配器,需要下面的步骤。
• 从压缩十进制源文件中读取。
• 基于相关的输入模版文件中的说明解压文件。
• 绑定解压后的数据到一个text数据类型列兵将它发送到下一个组件
就像前面讨论过的,有两个重要的过程来创建自定义组件。它们是设计时方法和运行时方法。下面是对这些虚方法的讨论。
[b]设计一个源适配器[/b]
在一个源适配器的设计阶段,第一步是定义和初始化组件的元数据。组件的元数据由以下组成:
• 组件的名称,描述,和自定义属性
• 组件的输入和输出集合,包括每个输入和输出的名称,描述,和属性
• 列集合包含在组件的每个输入和输出中,包括数据类型,尺寸,精度,和每列的长度,还有任何已经定义过的列级别的自定义属性
在设计时,组件的元数据通过使用ProvideComponentProperties()方法来定义。包调用ProvideComponentProperties()方法来初始化输入/输出集合和自定义属性。在设计阶段,这是用户添加组件到数据流任务中要调用的第一个方法。这个方法初始化组件属性,比如输入,输出,和自定义属性。虽然这个方法听上去像是一个构造函数,但它并不是一个确切的构造函数。在设计时实例或运行时实例的组件初始化的时候,它并不是每次都被调用。
下面是ProvideComponentProperties方法的代码。
public override void ProvideComponentProperties()
{
///Support resetting the component.
ComponentMetaData.RuntimeConnectionCollection.RemoveAll();
RemoveAllInputsOutputsAndCustomProperties();
// Add the Custom properties
IDTSCustomProperty90 tlogFile = ComponentMetaData.CustomPropertyCollection.New();
tlogFile.Description = "Specify the source TLOG file name
including the full path.";
tlogFile.Name = "TLogFile";
IDTSCustomProperty90 templateFile = ComponentMetaData.CustomPropertyCollection.New();
templateFile.Description = "Specify the template file name
including the full path.";
templateFile.Name = "TemplateFile";
IDTSOutput90 output = ComponentMetaData.OutputCollection.New();
output.Name = "TLOGOutput";
output.ExternalMetadataColumnCollection.IsUsed = true;
}
前两个方法,RemoveAllInputsOutputsAndCustomProperties()和ComponentMetaData.RuntimeConnectionCollection.RemoveAll()方法用来重置一个现有的组件的实例,它删除了定义的输入,输出,自定义属性,和连接。
为了连接到外部数据源,需要定义新的连接。首先应定义自定义属性。TLog源适配器包含了下列两个自定义属性。
• TLog压缩十进制文件的连接字符串。
• 模版文件的路径。
源适配器直接连接到数据源来提取数据。它通常是数据流图形布局中的第一个组件。因此,没有与上游组件相关的输入。
解压后的文件从自定义源适配器发送到下游的组件,如只有一行一列的DT_TEXT数据类型。这种发送整个解压后的数据作为一个单行的设计,用在输出中包含不同的行分隔符,并且有不同的列数时。转换数据为一个单行,使得在转换阶段处理数据很简单。因此,这里只定义了一个输出。您必须为任意输出列定义DataType, Length, Precision, 和CodePage属性。所有这些属性需都需要被设定,因为这些属性是只读的,并且每个都是独立的。这些属性可以通过调用SetDataTypeProperties()方法来设定。
注意:如果您不确定输出的正确格式,那么基类提供了以下三个方法。
• ConvertBufferDataTypeToFitManaged:取得DTS数据类型。
• BufferTypeToDataRecordType:基于一个DTS数据类型,返回一个托管数据类型。
• DataRecordTypeToBufferType:取得和一个托管类型相对应的DTS数据类型
自定义源适配器的另外两个需要重载的方法是Validate()和ReinitializeMetadata()方法。
PipelineComponent类的Validate()方法提供了验证,确保组件被正确配置。它检查输入和输出对象,包括列的数据类型。另外,它检查属性以确保它们是正确的。它检查自定义属性来保证输入值和连接字符串已经被赋值。当用户在设计状态下编辑组件时,这个方法每次都会被调用。它也会在运行时被调用。要看是否有错误,检查DTSValidationStatus枚举返回值的状态。您可以告知用户输入值或配置是否正确。
对于TLog源适配器组件,这个方法检查连接路径是否被正确配置。它也会检查来保证这些文件确实存在。基于它找到的错误的类型,Validate方法可以返回下面其中一种值。用户可以被警告或错误可以被校正。
• VS_NEEDSNEWMETADATA: 在组件元数据中存在一个错误,并且可以被组件本身修复。
• VS_ISBROKEN:组件包含一个错误,通过编辑组件,用户可以用Business Intelligence Development Studio中的SSIS设计器来修复。
• VS_ISCORRUPT:源代码的改变所带来的错误。要修复这种错误,开发人员必须删除并重建组件。
• VS_ISVALID: 组件被正确配置。
开发人员可以发送警告和错误给用户,使用FireWarning()和FireError()方法。
下面的代码用来验证TLog文件自定义属性的有效性。
#region Validate
[CLSCompliant(false)]
public override DTSValidationStatus Validate()
{
IDTSOutput90 output = ComponentMetaData.OutputCollection[0];
IDTSCustomProperty90 tlogFile = ComponentMetaData.CustomPropertyCollection["TLogFile"];
if (tlogFile.Value == null || ((String)tlogFile.Value).Length == 0)
{
ComponentMetaData.FireError(0, ComponentMetaData.Name, "TLOG file is required.", "", 0, out Cancel);
return DTSValidationStatus.VS_ISBROKEN;
}
else if (!File.Exists((String)tlogFile.Value))
{// TLog file name specified, verify it exists and is accessible
ComponentMetaData.FireError(0, ComponentMetaData.Name, String.Format("TLOG file '{0}' does not exist or is not accessible.", (String)tlogFile.Value), "", 0, out Cancel);
return DTSValidationStatus.VS_ISBROKEN;
}
// Validate the other properties
}
#end region
相似的代码用来验证模版文件的路径。这段代码也通过检查输出列的匹配,检查元数据是否正确。
if (ComponentMetaData.OutputCollection[0].OutputColumnCollection.Count == 0)
{
return DTSValidationStatus.VS_NEEDSNEWMETADATA;
}
/// Validate the output columns against the external metadata
if (ComponentMetaData.ValidateExternalMetadata)
{
if (!ComponentValidation.DoesExternalMetaDataMatchOutputMetaData(output))
{
ComponentMetaData.FireWarning(0, ComponentMetaData.Name, "The ExternalMetaDataColumns do not match the output columns.", "", 0);
return DTSValidationStatus.VS_NEEDSNEWMETADATA;
}
如果元数据不正确并且可以有组件修复,那么将返回VS_NEEDSNEWMETADATA枚举。要记住Validate()方法只能被用来引发错误。组件的状态不能再这个方法里修改。因为这个方法频繁的被编译器调用,所以在这个方法中改变组件将引发不可预知的行为。因此,错误应当在ReintializeMetaData()方法中被修改。例如,如果输出列的属性不正确,那么ReintializeMetaData()方法获得IDTSOutputColumn90对象,设定适当的数据类型,并将它与外部输入列的元数据进行匹配。代码如下。
public override void ReinitializeMetaData()
{
IDTSOutput90 output = ComponentMetaData.OutputCollection[0];
/// Start clean.
output.OutputColumnCollection.Removedll();
output.ExternalMetadataColumnCollection.RemoveAll();
IDTSOutputColumn90 outColumn = ComponentMetaData.OutputCollection[0].OutputColumnCollection.New();
IDTSCustomProperty90 dataSourceColumnName = outColumn.CustomPropertyCollection.New();
dataSourceColumnName.Name = "DataSourceColumnName";
dataSourceColumnName.Value = "DecodedString";
dataSourceColumnName.Description = "The name of the column at the data source.";
/// Set the output column's properties.
outColumn.Name = "DecodedString";
outColumn.SetDataTypeProperties(DataType.DT_TEXT, 0, 0, 0, 1252);
IDTSExternalMetadataColumn90 eColumn = output.ExternalMetadataColumnCollection.New();
eColumn.Name = outColumn.Name;
eColumn.DataType = outColumn.DataType;
eColumn.Precision = outColumn.Precision;
eColumn.Length = outColumn.Length;
eColumn.Scale = outColumn.Scale;
outColumn.ExternalMetadataColumnID = eColumn.ID;
}
[b]运行时[/b]
数据流引擎使用in-memory缓冲器在不同的组件之间移动数据。数据流引擎创建并管理用来传送数据的管道缓冲器。在执行时,输入和输出集合被分配,并且创建相关缓冲器。对于自定义源适配器来说,没有输入,只有输出被添加。输出被数据流任务分配,它分配Microsoft.SqlServer.Dts.Pipeline.PipelineBuffer.PipelineBuffer对象,它在数据流中包含所有需要的列。
Pre-Execute, PrimeOutput, 和ProcessInput都是运行时方法,它应当用来管理输入和输出。Pre-Execute在PrimeOutput和ProcessInput之前被调用。这个方法是您访问输出和输入集合的第一个机会。每个输入和输出集合都包含列集合。集合中的列是由它们的lineage ID唯一标识的。管道缓冲器在相关的缓冲列中,存储列数据。这些缓冲列由列索引来标识。如果在输入或输出集合中有多个列,为了定位特殊的输入或输出列,您必须在列集合中匹配列的lineage ID到相关缓冲器的列索引。这是因为在缓冲器中列的顺序和在输入或输出集合中的顺序不一致。要达到匹配,您必须在输出列集合中定位列的lineage ID。您可以使用Microsoft.SqlServer.Dts.Pipeline.PipelineComponent.BufferManager类的Microsoft.SqlServer.Dts.Pipeline.Wrapper.IDTSBufferManager90.FindColumnByLineageID(System.Int32,System.Int32)方法来访问lineage ID。这个lineage ID和缓冲器类型可以用来寻找列索引。
这个组件中没有输入,索引ProcessInput()没有被使用到。
下一个重要做定义源适配器的方法是PrimeOutput()方法。这个方法用来调用外部方法,来处理和管理输出。它添加行到输出缓冲器中,并发送数据到下游组件。这个方法初始化了一个TLogReader类型的对象,并调用多个方法以解压文件。TLog文件和模版文件通过自定义属性定义,并作为参数在TLogReader类的方法中出现。返回的输出被插入到输出缓冲器中。到缓冲器满了以后,数据就会被推到下游组件中进一步处理。
public override void PrimeOutput(int outputs, int[] outputIDs, PipelineBuffer[] buffers)
{
IDTSOutput90 output = ComponentMetaData.OutputCollection[0];
PipelineBuffer buffer = buffers[0];
try
{
buffer.AddRow();
TLOGReader reader = new TLOGReader();
IDTSCustomProperty90 tlogFile = ComponentMetaData.CustomPropertyCollection["TLogFile"];
IDTSCustomProperty90 templateFile = ComponentMetaData.CustomPropertyCollection["TemplateFile"];
reader.ProcessTLogFile(((String)tlogFile.Value), ((String)templateFile.Value));
buffer[0] = reader.ReaderOutout.ToString();
}
catch
{
}
finally
{
/// Notify the data flow that we are finished adding rows to the output.
buffer.SetEndOfRowset();
}
}
TLogReader类包含了解压压缩十进制文件的方法。压缩十进制文件中的数据作为一个二进制流被提取。Perl语言中包含函数叫做Pack()和Unpack()。Pack()取得一个数组或值的列表,并将它加入到一个二进制结构中,它返回包含这个结构的串。Unpack()并不是Pack()的反操作。它获得二进制结构并将它打开。这是要依据用来给数据打包的模版。这个模版是一个字符序列,它给出了值的顺序和类型。不幸的是,.NET Framework不包含任何相似的功能来通过模版解压二进制文件。因此,一个自定义的方法被实现,叫做Unpack。这个方法接受二进制数据和模版说明文件作为输入。模版包含了一个字符序列,它给出了值达顺序和类型。
模版文件用来解压压缩二进制文件,
"00" => ["H2","H4","H5","H6","H4","H8"]
"01" => ["H2","A12","H4”]
"03" => ["H2","A5","A12"]
其中
H: 一个十六进制串(高四位优先)。
A: 一个ASCII字符串。
数字: 包含特定编码的字节数。
像前面讨论过的,每行压缩数据的开头的两个十六进制的值,代表了模版的行类型,并定义了其他的说明来解析文件。基于这个说明,文件被解压。例如,如果模版文件指定前两个字符为十六进制(高四位优先),解压函数以前面的方式解压文件。
switch (FormatSpecifier[0])
{
case 'H': //Hex
String CurrentHex;
int HexStrLen = 0;
foreach (Byte CurrentByte in Bytes)
{
if (ExpectedCharCount != -1 && HexStrLen >= ExpectedCharCount)
break;
CurrentHex = String.Format("{0:X2}", CurrentByte).ToLower();
Result.Append(CurrentHex);
HexStrLen += 2;
}
break;
相似的,通过使用适当的编码,ASCII字符也被解压。结果集被追加为一个DT_TEXT数据类型。全部文件这样被解压,并且结果集被发送到输出管道缓冲器中。
解压后的文件的一个相同输出如下:
00:0006:0006:0408021033:00:32:101254:f42587:3297::f9:38::f433:","","99:ZIPCODE:11999","90:DESC:XYZ-24C BW","01:288206:1999:f130:000000:f128::00","90:DESC:XYZ ITEM,"01:112811:f790:f130:000011:f128::00”, "20:0023:0011:0408020945:10:101112:I:"
"20:0019:0011:0405020945:10:1012:I:"
[b]自定义TLog转换[/b]
使用自定义源适配器,数据被读取并从压缩十进制文件中提取。然后,它被解压。解压的数据被发送到自定义转换组件,这里可以解析数据。自定义转换收到一个单行单列作为输入,基于说明文件来解析数据到一个有意义并容易理解的格式。说明文件中包含了用来解析十六进制和ASCII字符到可识别的模版。这种说明文件被加载为一个.ini配置文件。
已解压的输入到TLog转换组件包含了拥有以下特征的行:
• 可以被一个逗号或行尾符来分隔的行。
• 用冒号分隔的行。
• 每行压缩数据的开头的两个十六进制的值,代表了模版的行类型,并定义了行中省下的数据的格式。
数据被读取,并且事务被分成多个输出。示例输出可能是标题信息,折扣信息,销售信息,或用户信息。
像前面讨论过的,POS应用程序可以保持一个文件打开很多天。或者,多个文件可能在同一个进程中被打开。一个文件的关闭被定义为一个关闭事务。
[b]设计一个异步转换组件[/b]
转换组件可以是同步的,也可以是异步的。如果一个组件,直到它已经接受了所有的输入行,还没能输出行,或当对于每一个接到的输入行,转换不能生成一个输出行,那么事务组件就被定义为异步的。在这个项目中,再定义源适配器以单行单列来发送数据。这个数据需要被解析到多个不同的输出中。整个输入被自定义TLog源适配器接收到,并处理,生成多个不同的行。这些行被冲定向到分别的输出。因此,TLog转换组件中的输出是异步的。
输入,输出,和自定义属性在ProvideComponentProperties方法中被定义。默认的,基类会创建一个输入和一个输出,并设定输出和输入是同步的。在这个项目中,因为输出式异步的,所以SynchronousInputID属性被设定为0。如下面的代码所示。
public override void ProvideComponentProperties()
{
/// Support resettability.
/// The base class calls RemoveAllInputsOutputsAndCustomProperties to reset the
/// component. Used here to highlight the functionality of the base class.
base.RemoveAllInputsOutputsAndCustomProperties();
// Let the base component add the input and output.
base.ProvideComponentProperties();
// Name the input and output, and make the output asynchronous.
ComponentMetaData.InputCollection[0].Name = "TLOG Input";
IDTSOutput90 headerOutput = ComponentMetaData.OutputCollection[0];
headerOutput.Name = "HeaderOutput";
headerOutput.Description = "Header rows are directed to this output.";
headerOutput.SynchronousInputID = 0;
/// Add the other outputs.
IDTSOutput90 closeOutput = ComponentMetaData.OutputCollection.New();
closeOutput.Name = "CloseOutput";
closeOutput.Description = "Close rows are directed to this output.";
…..
…..
…….//Other outputs are defined ….
…..
…..
///Add the custom property to the component
/// Config File is the ini template file. The TLog Parser will parse the files ///based on this template.
IDTSCustomProperty90 INIproperty = ComponentMetaData.CustomPropertyCollection.New();
INIproperty.Name = "Config File";
INIproperty.Description = " Ini file to process the tlog information";
/// Each TLog file is associated with a store.
IDTSCustomProperty90 StoreName = ComponentMetaData.CustomPropertyCollection.New();
StoreName.Name = "Store Name";
StoreName.Description = "Name of the store to be processed";
}
对于每个输出,处理过的行包含不同数量的列。因为输出每行包含的列数是不等的,所以为了简化实现,每行的所有行被追加为一个字符串。因此,每个输出有一个单列。通过使用内建的组件,输出数据可以被进一步的转换。
因为输出中只有一列,所以用户不允许在设计时从输出中添加或删除列。但是,用户可以处理任意数量的输出。因此,用户可以删除所有的他们不需要的输出。为了阻止用户从输出中添加或删除列,应重载InsertOutput()和DeleteOutputColumn()方法。
public override void DeleteOutputColumn(int outputID, int outputColumnID)
{
throw new Exception("Columns cannot be deleted. Remove the output instead");
}
在设计时,输出列基于输入列的属性来定义。可以使用PipelineComponent.SetUsageType()方法来创建输入到输出列的映射,同时也定义了输出列的数据类型和其它属性。
public override IDTSInputColumn90 SetUsageType(int inputID, IDTSVirtualInput90 virtualInput, int lineageID, DTSUsageType usageType)
{
IDTSVirtualInputColumn90 vCol = virtualInput.VirtualInputColumnCollection.GetVirtualInputColumnByLineageID(lineageID);
IDTSInputColumn90 col = null;
/// Only support for text columns.
if ((vCol.DataType != DataType.DT_TEXT))
throw new Exception("Only Text datatypes are supported.");
/// If the usageType is UT_IGNORED, then the column is being removed.
/// So throw the appropriate error
if (usageType == DTSUsageType.UT_IGNORED)
{
throw new Exception("columns cannot be removed");
}
else if (usageType == DTSUsageType.UT_READWRITE)
{
throw new Exception("Read write not supported.");
}
else
{
/// Let the base class add the input column.
col = base.SetUsageType(inputID, virtualInput, lineageID, usageType);
/// Add an output column
AddOutputColumn(ComponentMetaData.OutputCollection[0].ID, col);
AddOutputColumn(ComponentMetaData.OutputCollection["CloseOutput"].ID, col);
………….
………..
…………………// to add additional output columns to the outputCollection
………..
……..
}
return col;
}
[b]异步组件的运行时方法[/b]
当包被执行时,会调用运行时方法。在执行时,输出和输入集合可以被第一次访问是在PreExecute()方法中。自定义源适配器和自定义转换组件的区别在于来自上游组件的输入行。对于源适配器来说没有输入。它直接连接外部数据源。自定义转换组件从上游组件中接收输入,处理数据,并将他发送给下游组件。如果输出是同步的,那么允许简单的‘row in and row out’方式。对于异步输出来说,因为输入集合不同于输出集合,所以不同的管道缓冲器会为这些输出和输入创建。
注意:如果转换组件是同步的,那么在数据被处理之后,相同的输入行作为一个输出行发送。因为对每个输入都有一个输出,所以相同的输入缓冲器可以被重用,来存储输出,并且缓冲器包含了整个列集合。一个单独的缓冲器在输入和输出之间被共享。缓冲器包含的列同时为输入和输出服务。
对于异步的组件,当在ProcessInput()方法中上游组件的输出缓冲器满了的时候,输入行(来自上游组件的输出行)被输入缓冲器接收到。ProcessInput()和PrimeOutput()方法的区别在于,除了处理输入和输出行,只要缓冲器向它传送数据,ProcessInput()将被重复的调用,而PrimeOutput()只调用一次。当管道缓冲器已满,数据被推向下游组件。在最后一行后面,EndofRowset属性被设为true。这暗示下游组件,输入行已经完成。相似的,输入行被处理直到遇到EndofRowset。对于TLog转换,只有一个来自上游源适配器的输入。
因为EndofRowset属性定义了输入行的结尾,开发人员需要在所有的行已经处理完成后,为输出行设定该属性。这是通过调用SetEndofRowset()方法来实现的。下面的代码显示了ProcessInput()方法的实现。
public override void ProcessInput(int inputID, PipelineBuffer buffer)
{
try
{
//Read all the rows of the input before processing
if(!buffer.EndOfRowset)
{
IDTSInput90 input = ComponentMetaData.InputCollection.GetObjectByID(inputID);
while (buffer.NextRow())
TinputBuffer = buffer.GetString(0);
}
if (!buffer.EndOfRowset)
{
//Extract the custom property for the config file
IDTSCustomProperty90 INIFile = ComponentMetaData.CustomPropertyCollection["Config File"];
//Extract the custom property of store name
//Call the TLog parser
PipelineBuffer[] buffers = new PipelineBuffer[_Buffers.Count];
IDictionaryEnumerator myEnumerator = _Buffers.GetEnumerator();
//Set the endofrowset for all the output buffers
while (myEnumerator.MoveNext())
{
PipelineBuffer NextBuffer = (PipelineBuffer)myEnumerator.Value;
if (NextBuffer != null)
NextBuffer.SetEndOfRowset();
}
}
}
catch
{
throw new Exception("Error in processing the file");
}
TLog解析器接收来自源适配器的解压后的字符串作为输入,并接收.ini配置文件作为另一个输入。它基于.ini配置文件中提供的说明来处理行。下面是.ini文件中的示例说明。
[00] Filename="Header Item" DelimiterCharacter="," Outputs="%store,0-2-2,0-1-0,0-2,----------------------------
[03] Filename="Sales Receipt"
DelimiterCharacter="," Outputs="%store,3-0,3-1,………………………………..
.ini文件中的第二个参数暗示行分隔符是一个逗号。基于这个分隔符,许多行从来自上游源适配器的单行数据中被提取出来。
一旦行被TLog自定义转换解析出来,PrimeOutput()方法将被调用,来为每个选择的输出分配输出缓冲器。每个输出被分配到一个相等的缓冲器。对于TLog解析转换,输出作为一个单行推到了下游组件中。像我们在Designing an asynchronous transformation component中讨论过的那样,这个设计逻辑被采取了,因为每行都包含一个列数不同的输出。
#region PrimeOutput
#region PrimeOutput
/// <summary>
/// The data flow task provides a buffer for each output
/// that is connected to a downstream component.
public override void PrimeOutput(int outputs, int[] outputIDs, PipelineBuffer[] buffers)
{
_Buffers = new Hashtable();
for (int x = 0; x < outputIDs.Length; x++)
{
IDTSOutput90 output = ComponentMetaData.OutputCollection.GetObjectByID(outputIDs[x]);
switch (output.Name)
{
case "HeaderOutput":
HeaderBuffer = buffers[x];
_Buffers.Add("HeaderOutput", (PipelineBuffer)this.HeaderBuffer);
break;
……………..
……………
……………..//TODO: Add the other output selected by the user during design // stage and assign the buffer
………..
……….
}//end of switch
} //end of loop
} //end of PrimeOutput
解压并转换后的数据为:
1,00,0004,0402030853,03,6,0,0,0,0,0,0,2628,0,0,1,0,0,0
1,1,01,0004,0005,0402030910,222222,1500,000000,128,0,0,0,0
[[i] 本帖最后由 xiaoxinlucky 于 2008-1-8 16:13 编辑 [/i]] |
| xiaoxinlucky | | 2008-1-8 08:21 |
|
[b]部署[/b]
完成编码之后,需要在SQL Server Integration Services中部署组件。一旦代码被验证无误,每个组件会被编译到不同的DLL中。一定要确保开发人员具有适当的安全权限,来访问引用的库,拷贝程序集到GAC和管道组件目录中,以及在SSIS中创建包。既然程序集需要被保存到GAC中,每个程序集都应该赋一个强名称。
下面部署一个管道组件所需要的步骤。
1. 为程序集创建一个强名称。
2. 编译任务。
3. 将任务移动到适当的目录中。
4. 添加任务到SSIS工具箱中。
5. 使用自定义组件创建包。
本小节描述了每个必须的步骤。
[b]为程序集创建强名称[/b]
因为程序集需要在应用程序之间共享,所以除了组件目录以外,它必须被复制到GAC中。只有当程序集有强名称时,他们才能被复制到GAC中。这必须是一个完全限定名,包括程序集的名称,区域和语言信息,公钥,和版本号。这保证了程序集是全局唯一的。您可以使用轻名称工具(sn.exe)来生成一个强名称。
强名称工具生成了一个公/私密钥。这个密钥对在编译时被用来创建一个强名称程序集。工具可以从命令行执行,这时需要指定包含密钥对的输出文件的名称。制定包含密钥对的输出文件的路径可以有两种方法。您可以编辑AssemblyInfo.cs文件,或使用Assembly Linker Tool (Al.exe)。下面的代码是AssemblyInfo.cs文件中的代码。它包含了密钥文件的路径。
[assembly:AssemblyKeyFileAttribute(@”..\..\TLogprocess.snk”)]
另外,当项目被编译时,版本号不能改变。可以在AssemblyInfo.cs文件中指定一个恒定的版本好。下面的代码标识版本号保持不变。
[assembly:AssemblyVersion("1.0.0.0")]
[b]编译任务[/b]
项目可以在Visual Studio 2005中编译,或者在命令提示符中编译。
要在Visual Studio 2005中编译TLog transformation task
1. 在File 菜单,选择Open, 然后选择Project.
2. 打开TLogProcess.csproj 项目.
注意: TLog transformation task项目名称为TLogProcess.
3. 按F5,或在Debug 菜单上单击Start来编译和运行项目.
To compile the file using the command prompt用命令提示符来编译文件
1. 用Change Directory 命令来改变到包含自定义组件项目的目录.
2. 输入下列命令.
for /r %f in (*.sln) do msbuild.exe "%f"
将任务移动到适当的目录中
在SSIS安装的过程中,单独的目录被创建来管理任务和管道组件的程序集。对于管道组件来说,默认的路径是%SystemDrive%:\Program Files\Microsoft SQL Server\90\DTS\PipelineComponents。在任务被编译后,将程序集文件(.dll)复制到这个目录下。
因为这些程序集必须被共享,所以有必要在GAC中保存一个程序集文件的副本。这些程序集已经被签名过了。要将文件复制到GAC中,您可以用命令行工具gacutil.exe或托拽程序集到%system%\assembly目录下。
用下面的命令来使用命令行工具,gacutil.exe,来复制文件。
gacutil.exe -iF "<assembly path>"
[b]添加任务到SSIS工具箱中[/b]
一旦程序集被编译,并复制到适当的目录下,最后一个工作就是将它们添加到SSIS工具箱中,以便用户可以访问到这些自定义组件。将组件放在目录中,并不会让它们在工具箱中显示可用。SQL Server Integration Services (原来是DTS Server)缓存了关于任务和组件的信息,因为列举它们是非常耗费资源的。因此,开发人员需要重启服务,来获得组件的新列表。一旦服务被重启,就可以访问任务了。
访问自定义组件
1. 在主菜单上右击Tools. 选择Toolbox items.
2. 在Choose Toolbox Items 对话框中, 选择SSIS Data Flow Items标签.
3. 为您需要在Business Intelligence Development Studio 的SSIS设计器中看到的组件,选择相应的复选框。
如图5所示,选择TLogSource(源适配器)和TLogProcess(转换)组件,允许用户在SSIS设计器中看到这些组件。
[img]http://298853.blog.51cto.com/album/288853/119978010835.jpg[/img]
Figure 5: Selecting the custom components in Toolbox for display
Now users can view the components in the Toolbox when they open the SSIS Designer. Of course, they must have appropriate permissions to work with the SSIS Designer and to access tasks on the machine. The user can drag and use these components the same as any other built-in component. Once the custom properties are assigned, the components are ready to execute.
[b]使用自定义组件创建包[/b]
本小节囊括了怎样用自定义组件创建一个数据流任务。在这个示例中,我们使用自定义的源适配器创建了一个示例包,用来解压一个压缩十进制文件,用自定义TLog转换组件解析它,并将它写入直接文件中。
添加自定义组件到包中
1. 要打开Business Intelligence Development Studio,打开Programs菜单,选择Microsoft SQL Server 2005 CTP,选择Business Intelligence Development Studio。
2. 在File 菜单中, 选择New, 然后选择Project. 对于项目类型, 选择Business Intelligence Projects.
3. 在New Project Templates 对话框中, 选择Integration Services Project.
4. 提供项目的Name, Location, 和Solution Name. Package Design Editor将会被打开.
5. 在Business Intelligence Development studio中,从Toolbox SSIS 设计器添加Data Flow task.
6. 打开Data Flow Task Editor. 从Data Flow Task Editor的Toolbox中,选择并添加TLog Source Adapter 到窗体中.
7. 右击TLog Source Adapter component 并选择Show Advanced Editor 如图6所示.
[img]http://298853.blog.51cto.com/album/288853/119978011164.jpg[/img]
图6: 添加TLog 源组件
8. 在Advanced Editor for TLog Source 窗口中, 给custom properties赋值.设定压缩十进制文件的连接路径和模版文件的连接路径,如图7所示。
[img]http://298853.blog.51cto.com/album/288853/119978011458.jpg[/img]
图7: 为TLog 源适配器设定custom properties
9. 确保Column Mappings标签和Input and Output Properties标签中的信息被设定正确。在Source Adapter中点击Column Mappings,并选择包含输入列。如图8:
[img]http://298853.blog.51cto.com/album/288853/119978011732.jpg[/img]
图8: 映射输入列到输出集合。
10. 接下来,选择ProcessTLog任务(ProcessTLog是TLog转换组件的名称)。连接TLog源适配器的输出到ProcessTLog组件。
11. 打开ProcessTLog组件的高级属性编辑器。在Custom Properties标签下,设定Config File属性为.ini配置文件的路径,并设定Store Name属性。如图9所示。
[img]http://298853.blog.51cto.com/album/288853/119978012004.jpg[/img]
图9: TLog 转换任务的属性
12. 选择Input and Output Properties标签。这个标签包含所有的输出。这个自定义转换组件已经被实现,并组织用户删除输出列。如果用户尝试删除输出列,如图10所示,将会显示一个错误消息。但是要注意,虽然不允许您从定义的输出中删除列,但是您可以删除整个输出。
[img]http://298853.blog.51cto.com/album/288853/119978012329.jpg[/img]
图 10: 当用户尝试删除一个输出列时会出现一个错误消息。
如图11所示,除了24个输出之外,只有Header 和Close输出被选择为向下游发送数据。同样如图11所示,输出列的属性窗口显示了列的数据类型和其他属性。
[img]http://298853.blog.51cto.com/album/288853/119978012687.jpg[/img]
图11: 转换组件的输出列的属性
13. 为了从压缩十进制文件中提取数据并保存到目标直接文件中,应选择Flat File Destination Adapter。当自定义的TLog转换的输出被连接到Flat File destination时,允许用户选择用哪一个输出来连接。如图12所示。
[img]http://298853.blog.51cto.com/album/288853/119978012996.jpg[/img]
图12: 选择输出来映射到目标
14. 为了在一个文件中储存Header信息,需要为Flat File Destination指定文件连接和映射。
15. 运行包。输出被存储在Header直接文件中,如图13所示。
[img]http://298853.blog.51cto.com/album/288853/119978013208.jpg[/img]
图13: 成功的完成TLog 压缩十进制文件的数据流
[b]调试[/b]
需要强调的是,您的代码在投放生产环境之前,必须经过完全的测试。开发人员应当首先检查代码的语法的正确性和基本逻辑。编译程序,以保证语法上的争取。对于语义验证,开发人员需要验证代码的正确性,可以通过附加进程并设定适当的断点来实现。实现的组件寄宿在应用程序中,比如Business Intelligence Development Studio,并可以通过关联源代码和相应的进程来实现调试。在Visual Studio开发环境中,可以在不同的位置设定断点,并检查输出数据以保证实现的逻辑按期望的方式工作。
实现的自定义组件的运行时方法的调试调试,可以通过DTEXEC命令行工具来运行包。
使用DTEXEC运行包
16. 使用实现的自定义组件创建一个SSIS包
17. 打开Visual Studio 并打开自定义组件的项目
18. 选择Project, 然后选择<projectname> Properties.
19. 设定项目为Debug模式.
20. 选择DEBUG属性.
21. 设定下列属性.
Mode: Debug
Start external program: <path to the exe>\DTEXEC.exe
Command line arguments: /f “<pathtoyourSSISpackage>"
[img]http://298853.blog.51cto.com/album/288853/119978014173.jpg[/img]
图14: 设定Debug属性
DTEXEC是一个命令行工具,用来运行DTS包。在实现代码中,在适当的方法上设定断点和监视点。当代码在Debug模式中使用F5或Start被执行时,DTEXEC运行相关的SSIS包。您可以调试输出值以保证代码的可靠性和正确性。
您也可以通过附加源代码到DtsDebugHost.exe进程中,来调试一个正在运行的包的运行时的方法。对于这种方法,应当在包的执行过程中引入一个暂停。当包的执行被暂停后,DTSDebugHost.exe可以被附加,并且源代码可以通过插入断点到适当的位置被调适。
您同样可以在Business Intelligence Development Studio中设定调试属性。例如两个数据流任务之间的数据查看器,您可以设定它来监视流向下游的数据和转换的行/列数。在这个项目中,TLog转换任务解析并发送大约338行数据到Header文件中。如图15所示,您可以查看行的内容,来验证数据。另外,数据察看器指示了向下一个组件转换的行数。数据查看器可以被用作为一个很好的调试工具。
[img]http://298853.blog.51cto.com/album/288853/119978014518.jpg[/img]
图 15: 在数据查看器中显示的输出
当自定义组件被适当的编码,测试,和部署,它们就可以被用作任意其它的内建数据流组件。
[b]收获[/b]
对于Project REAL,要提高ETL包的效率和性能,我们决定将压缩十进制文件的解析包含在SSIS管道本身中。为了实现它,我们需要实现自定义组件。
对于设计自定义组件,最初的挑战是理解新的SSIS对象模型和编程特性。理解那一个接口和方法需要重载是开发一个自定义组件的首要问题。当我们实现这些自定义组件时,我们惊人的发现,扩展现有的模型来创建自定义任务和容器是那么的容易!除了理解和扩展SSIS对象模型,对于这些自定义组件的成功实现,解压和解析压缩十进制TLog文件是十分必要的。我们不得不实现自定义方法来解压和解析数据到需要的格式。
下面是一些我们在课程进行中的收获的汇总。
• 为了保证适当的执行,组件必须被正确的配置。开发人员应当确保适当的输入和输出集合被配置。任何附加的属性,都需要适当地配置,可能使用自定义属性来配置。这些属性是早期定义在ProvideComponentProperties()方法中,并且使用Validate()方法来验证的。
• 源适配器的外部数据源,需要使用ConnectionManagers类或自定义属性来定义。
• 实现一个自定义组件包括设计时和运行时的设计。在设计时,原数据可能被频繁改变。因此,当您实现设计时方法时,灵活性是设计的一个重要准则。添加或删除输出或输入列,或改变原数据不应当破坏组件。适当的验证方法和错误消息必须集成在设定中,保证输入和外部资源被验证。
• 一个重要的方法是Validate()方法,它保证资金被正确配置。我们记得一个重要的事情是,Validate()方法只能用于验证争取的配置和引发错误事件。使用这个方法,错误将不会被固定。需要记住的一条规则是,不要再Validate()方法中改变组件的状态。
• 当设计运行时方法时,管道缓冲器是一个需要考虑的非常重要的因素。第一步是决定您的自定义组件是要同步还是要异步。如果组件是同步的,那么输出和输入将使用相同的缓冲器。如果组件是异步的,那么使用PrimeOutput()方法来制定与输出相关的管道缓冲器。因此,一个异步组件,是一个从ProcessInput()接收数据并从PrimeOutput()发送数据的数据流组件。
• 在这个项目中我们面对的主要的挑战,是TLog转换组件有24个输出(如果用户选择使用所有的24个输出)。为了保证适当的数据流,24个管道缓冲器需要被初始化。另外,为了提取正确的数据,需要的输出的列必须和相关的列的索引完全匹配。
• SQL Server Integration Services (原来是DTS Server)在工具箱中缓存所有的任务和组件的信息。这阻止了代价高昂的枚举。对于部署来说,如果SQL Server Integration Services被启用,那么service必须被重启来包含新部署的自定义组件。
• 对于部署来说,要确保自定义组件的开发人员拥有必须的权限,将程序集复制到GAC和管道组件目录中。自定义组件需要复制到这两个目录才行。
结论
新的SSIS对象模型已经被重新设计,并具有很强的可扩展性。因为对象模型可以使用托管语言进行扩展,所以您可以简单的创建您自己的自定义任务,组件,或定制任意SSIS模型中的对象。本文论证了一个可扩展机制的应用程序-它从一个不常见的格式中加载数据,并将他直接加载到生产数据仓库中。当处理数据时,这种新的机制消除了中间存储和处理。这使我们能够获得一个性能更好,更易维护的系统。这些机制很容易学习。您可以通过管道缓冲区的最优使用,优化您的数据流的性能。这保证了加载数据到数据仓库中时,获得更加可管理性,性能,灵活性,和一个强壮的ETL处理。 |
关键词: C NAT
相关文章: ASP.net运行问题 vlan+NAT 企业信息化,如何迈出第一步 网络监控软件的延伸运用
Powered by 51CTO.COM
|