사용자 지정 원본 구성 요소 개발Developing a Custom Source Component

SQL ServerSQL Server Integration ServicesIntegration Services 에서는 개발자가 사용자 지정 데이터 원본에 연결 하 고 데이터 흐름 태스크의 다른 구성 요소에 이러한 원본에서 데이터를 제공할 수 있는 원본 구성 요소를 작성할 수 있습니다. Integration ServicesIntegration Services gives developers the ability to write source components that can connect to custom data sources and supply data from those sources to other components in a data flow task. 사용자 지정 원본을 만드는 기능은 기존 Integration ServicesIntegration Services 원본 중 하나를 사용하여 액세스할 수 없는 데이터 원본에 연결해야 하는 경우에 유용합니다.The ability to create custom sources is valuable when you must connect to data sources that cannot be accessed by using one of the existing Integration ServicesIntegration Services sources.

원본 구성 요소에는 하나 이상의 출력이 있으며 입력은 없습니다.Source components have one or more outputs and zero inputs. 디자인 타임에 원본 구성 요소는 연결을 만들어 구성하고, 외부 데이터 원본에서 열 메타데이터를 읽고, 외부 데이터 원본을 기반으로 원본의 출력 열을 구성하는 데 사용됩니다.At design time, source components are used to create and configure connections, read column metadata from the external data source, and configure the source's output columns based on the external data source. 실행 중 원본 구성 요소는 외부 데이터 원본에 연결하고 출력 버퍼에 행을 추가합니다.During execution they connect to the external data source and add rows to an output buffer. 그런 다음 데이터 흐름 태스크에서는 다운스트림 구성 요소에 이 데이터 행 버퍼를 제공합니다.The data flow task then provides this buffer of data rows to downstream components.

데이터 흐름 구성 요소 개발의 일반적인 개요를 참조 하십시오. 사용자 지정 데이터 흐름 구성 요소 개발합니다.For a general overview of data flow component development, see Developing a Custom Data Flow Component.

디자인 타임Design Time

원본 구성 요소의 디자인 타임 기능을 구현하려면 외부 데이터 원본에 대한 연결을 지정하고, 데이터 원본을 반영하는 출력 열을 추가 및 구성하고, 구성 요소를 실행할 준비가 되었는지 확인해야 합니다.Implementing the design-time functionality of a source component involves specifying a connection to an external data source, adding and configuring output columns that reflect the data source, and validating that the component is ready to execute. 정의에 따라 원본 구성 요소에는 입력이 없으며 하나 이상의 비동기 출력이 있습니다.By definition, a source component has zero inputs and one or more asynchronous outputs.

구성 요소 만들기Creating the Component

원본 구성 요소는 패키지에 정의된 ConnectionManager 개체를 사용하여 외부 데이터 원본에 연결합니다.Source components connect to external data sources by using ConnectionManager objects defined in a package. 원본 구성 요소에서는 RuntimeConnectionCollection 속성의 ComponentMetaData 컬렉션에 요소를 추가하여 연결 관리자가 필요함을 나타냅니다.They indicate their requirement for a connection manager by adding an element to the RuntimeConnectionCollection collection of the ComponentMetaData property. 이 컬렉션은 두 가지 용도로 사용됩니다. 첫 번째는 구성 요소에서 사용하는 패키지에 연결 관리자에 대한 참조를 저장하는 것이고 다른 하나는 디자이너에 연결 관리자가 필요함을 알리는 것입니다.This collection serves two purposes—to hold references to connection managers in the package used by the component, and to advertise the need for a connection manager to the designer. 경우는 IDTSRuntimeConnection100 를 컬렉션에 추가 되었습니다는 고급 편집기 표시는 연결 속성 탭을 선택 하거나 패키지에 대 한 연결을 만들 수 있습니다.When an IDTSRuntimeConnection100 has been added to the collection, the Advanced Editor displays the Connection Properties tab, which lets users select or create a connection in the package.

다음 코드 예에서는 출력을 추가하고 ProvideComponentPropertiesIDTSRuntimeConnection100 개체를 추가하는 RuntimeConnectionCollection의 구현을 보여 줍니다.The following code example shows an implementation of ProvideComponentProperties that adds an output, and adds a IDTSRuntimeConnection100 object to the RuntimeConnectionCollection.

using System;  
using System.Collections;  
using System.Data;  
using System.Data.SqlClient;  
using System.Data.OleDb;  
using Microsoft.SqlServer.Dts.Runtime;  
using Microsoft.SqlServer.Dts.Runtime.Wrapper;  
using Microsoft.SqlServer.Dts.Pipeline;  
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;  

namespace Microsoft.Samples.SqlServer.Dts  
{  
    [DtsPipelineComponent(DisplayName = "MySourceComponent",ComponentType = ComponentType.SourceAdapter)]  
    public class MyComponent : PipelineComponent  
    {  
        public override void ProvideComponentProperties()  
        {  
            // Reset the component.  
            base.RemoveAllInputsOutputsAndCustomProperties();  
            ComponentMetaData.RuntimeConnectionCollection.RemoveAll();  

            IDTSOutput100 output = ComponentMetaData.OutputCollection.New();  
            output.Name = "Output";  

            IDTSRuntimeConnection100 connection = ComponentMetaData.RuntimeConnectionCollection.New();  
            connection.Name = "ADO.NET";  
        }  
Imports System.Data  
Imports System.Data.SqlClient  
Imports Microsoft.SqlServer.Dts.Runtime  
Imports Microsoft.SqlServer.Dts.Runtime.Wrapper  
Imports Microsoft.SqlServer.Dts.Pipeline  
Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper  

<DtsPipelineComponent(DisplayName:="MySourceComponent", ComponentType:=ComponentType.SourceAdapter)> _  
Public Class MySourceComponent  
    Inherits PipelineComponent  

    Public Overrides Sub ProvideComponentProperties()  

        ' Allow for resetting the component.  
        RemoveAllInputsOutputsAndCustomProperties()  
        ComponentMetaData.RuntimeConnectionCollection.RemoveAll()  

        Dim output As IDTSOutput100 = ComponentMetaData.OutputCollection.New()  
        output.Name = "Output"  

        Dim connection As IDTSRuntimeConnection100 = ComponentMetaData.RuntimeConnectionCollection.New()  
        connection.Name = "ADO.NET"  

    End Sub  
End Class  

외부 데이터 원본에 연결Connecting to an External Data Source

RuntimeConnectionCollection에 연결을 추가한 후에는 AcquireConnections 메서드를 재정의하여 외부 데이터 원본에 대한 연결을 설정합니다.After a connection has been added to the RuntimeConnectionCollection, you override the AcquireConnections method to establish a connection to the external data source. 이 메서드는 디자인 및 실행 중에 호출됩니다.This method is called during both design and execution time. 구성 요소에서는 런타임 연결에 지정된 연결 관리자에 대한 연결을 설정한 후 외부 데이터 원본에 대한 연결을 설정해야 합니다.The component should establish a connection to the connection manager specified by the run-time connection, and subsequently, to the external data source.

연결이 설정되면 구성 요소에서는 연결을 내부에 캐시했다가 ReleaseConnections 메서드가 호출되면 이를 해제해야 합니다.After the connection is established, it should be cached internally by the component and released when the ReleaseConnections method is called. ReleaseConnections 메서드는 AcquireConnections 메서드와 마찬가지로 디자인 및 실행 중에 호출됩니다.The ReleaseConnections method is called at design and execution time, like the AcquireConnections method. 개발자는 이 메서드를 재정의하고 AcquireConnections 실행 중에 구성 요소에서 설정한 연결을 해제합니다.Developers override this method, and release the connection established by the component during AcquireConnections.

다음 코드 예에서는 AcquireConnections 메서드에서 ADO.NET 연결에 연결한 다음 ReleaseConnections 메서드에서 연결을 닫는 구성 요소를 보여 줍니다.The following code example shows a component that connects to an ADO.NET connection in the AcquireConnections method and closes the connection in the ReleaseConnections method.

private SqlConnection sqlConnection;  

public override void AcquireConnections(object transaction)  
{  
    if (ComponentMetaData.RuntimeConnectionCollection[0].ConnectionManager != null)  
    {  
        ConnectionManager cm = Microsoft.SqlServer.Dts.Runtime.DtsConvert.GetWrapper(ComponentMetaData.RuntimeConnectionCollection[0].ConnectionManager);  
        ConnectionManagerAdoNet cmado = cm.InnerObject as ConnectionManagerAdoNet;  

        if (cmado == null)  
            throw new Exception("The ConnectionManager " + cm.Name + " is not an ADO.NET connection.");  

        sqlConnection = cmado.AcquireConnection(transaction) as SqlConnection;  
        sqlConnection.Open();  
    }  
}  

public override void ReleaseConnections()  
{  
    if (sqlConnection != null && sqlConnection.State != ConnectionState.Closed)  
        sqlConnection.Close();  
}  
Private sqlConnection As SqlConnection  

Public Overrides Sub AcquireConnections(ByVal transaction As Object)  

    If Not IsNothing(ComponentMetaData.RuntimeConnectionCollection(0).ConnectionManager) Then  

        Dim cm As ConnectionManager = Microsoft.SqlServer.Dts.Runtime.DtsConvert.GetWrapper(ComponentMetaData.RuntimeConnectionCollection(0).ConnectionManager)  
        Dim cmado As ConnectionManagerAdoNet = CType(cm.InnerObject, ConnectionManagerAdoNet)  

        If IsNothing(cmado) Then  
            Throw New Exception("The ConnectionManager " + cm.Name + " is not an ADO.NET connection.")  
        End If  

        sqlConnection = CType(cmado.AcquireConnection(transaction), SqlConnection)  
        sqlConnection.Open()  

    End If  
End Sub  

Public Overrides Sub ReleaseConnections()  

    If Not IsNothing(sqlConnection) And sqlConnection.State <> ConnectionState.Closed Then  
        sqlConnection.Close()  
    End If  

End Sub  

출력 열 만들기 및 구성Creating and Configuring Output Columns

원본 구성 요소의 출력 열은 실행 중 구성 요소에서 데이터 흐름에 추가하는 외부 데이터 원본의 열을 반영합니다.The output columns of a source component reflect the columns from the external data source that the component adds to the data flow during execution. 디자인 타임에는 구성 요소가 외부 데이터 원본에 연결하도록 구성된 후 출력 열을 추가해야 합니다.At design time, you add output columns after the component has been configured to connect to an external data source. 구성 요소에서 출력 컬렉션에 열을 추가하는 데 사용하는 디자인 타임 메서드는 구성 요소의 요구 사항에 따라 달라질 수 있지만 Validate 또는 AcquireConnections 실행 중에는 디자인 타임 메서드를 추가하면 안 됩니다.The design-time method that a component uses to add the columns to its output collection can vary based on the needs of the component, although they should not be added during Validate or AcquireConnections. 예를 들어 구성 요소의 데이터 집합을 제어하는 사용자 지정 속성에서 SQL 문이 포함된 구성 요소는 SetComponentProperty 메서드 실행 중 출력 열을 추가할 수 있습니다.For example, a component that contains a SQL statement in a custom property that controls the data set for the component may add its output columns during the SetComponentProperty method. 구성 요소에서는 캐시된 연결이 있는지 여부를 확인하고, 캐시된 연결이 있으면 데이터 원본에 연결하여 출력 열을 생성합니다.The component checks to see whether it has a cached connection, and, if it does, connects to the data source and generates its output columns.

출력 열이 만들어진 후에는 SetDataTypeProperties 메서드를 호출하여 해당 데이터 형식 속성을 설정합니다.After an output column has been created, set its data type properties by calling the SetDataTypeProperties method. DataType, Length, PrecisionCodePage 속성은 읽기 전용이고 각기 다른 속성의 설정에 따라 달라지므로 이 메서드가 필요합니다.This method is necessary because the DataType, Length, Precision, and CodePage properties are read-only and each property is dependent on the settings of the other. 이 메서드는 이러한 값이 일관성 있게 설정되도록 하며 데이터 흐름 태스크에서는 해당 값이 올바르게 설정되어 있는지 확인합니다.This method enforces the need for these values to be set consistently, and the data flow task validates that they are set correctly.

열의 DataType은 다른 속성에 대해 설정되는 값을 결정합니다.The DataType of the column determines the values that are set for the other properties. 다음 표에서는 각 DataType의 종속 속성에 대한 요구 사항을 보여 줍니다.The following table shows the requirements on the dependent properties for each DataType. 이 목록에 포함되지 않은 데이터 형식의 종속 속성은 0으로 설정됩니다.The data types not listed have their dependent properties set to zero.

DataTypeDataType 길이Length 소수 자릿수Scale 전체 자릿수Precision CodePageCodePage
DT_DECIMALDT_DECIMAL 00 0보다 크고 28보다 작거나 같습니다.Greater than 0 and less than or equal to 28. 00 00
DT_CYDT_CY 00 00 00 00
DT_NUMERICDT_NUMERIC 00 0보다 크고 28보다 작거나 같으며 Precision보다 작습니다.Greater than 0 and less than or equal to 28, and less than Precision. 1보다 크거나 같고 38보다 작거나 같습니다.Greater than or equal to 1 and less than or equal to 38. 00
DT_BYTESDT_BYTES 0보다 큽니다.Greater than 0. 00 00 00
DT_STRDT_STR 0 보다 작은 8000 보다 크고 합니다.Greater than 0 and less than 8000. 00 00 0이 아니며 올바른 코드 페이지가 아닙니다.Not 0, and a valid code page.
DT_WSTRDT_WSTR 0보다 크고 4000보다 작습니다.Greater than 0 and less than 4000. 00 00 00

데이터 형식 속성에 대한 제한 사항은 출력 열의 데이터 형식을 기준으로 하므로 관리되는 형식을 사용할 때는 올바른 SSISSSIS 데이터 형식을 선택해야 합니다.Because the restrictions on the data type properties are based on the data type of the output column, you must choose the correct SSISSSIS data type when you work with managed types. 세 가지 도우미 메서드를 제공 하는 기본 클래스 ConvertBufferDataTypeToFitManaged, BufferTypeToDataRecordType, 및 DataRecordTypeToBufferType, 선택 하는 관리 되는 구성 요소 개발자를 지원 하기 위해 프로그램 SSISSSIS 관리 되는 형식이 지정 된 데이터 형식입니다.The base class provides three helper methods, ConvertBufferDataTypeToFitManaged, BufferTypeToDataRecordType, and DataRecordTypeToBufferType, to assist managed component developers in selecting an SSISSSIS data type given a managed type. 이러한 메서드는 관리되는 데이터 형식을 SSISSSIS 데이터 형식으로 변환하거나 그 반대로 변환합니다.These methods convert managed data types to SSISSSIS data types, and vice versa.

다음 코드 예에서는 테이블의 스키마를 기반으로 구성 요소의 출력 열 컬렉션을 채우는 방법을 보여 줍니다.The following code example shows how the output column collection of a component is populated based on the schema of a table. 기본 클래스의 도우미 메서드는 열의 데이터 형식을 설정하는 데 사용되며 종속 속성은 해당 데이터 형식에 따라 설정됩니다.The helper methods of the base class are used to set the data type of the column, and the dependent properties are set based on the data type.

SqlCommand sqlCommand;  

private void CreateColumnsFromDataTable()  
{  
    // Get the output.  
    IDTSOutput100 output = ComponentMetaData.OutputCollection[0];  

    // Start clean, and remove the columns from both collections.  
    output.OutputColumnCollection.RemoveAll();  
    output.ExternalMetadataColumnCollection.RemoveAll();  

    this.sqlCommand = sqlConnection.CreateCommand();  
    this.sqlCommand.CommandType = CommandType.Text;  
    this.sqlCommand.CommandText = (string)ComponentMetaData.CustomPropertyCollection["SqlStatement"].Value;  
    SqlDataReader schemaReader = this.sqlCommand.ExecuteReader(CommandBehavior.SchemaOnly);  
    DataTable dataTable = schemaReader.GetSchemaTable();  

    // Walk the columns in the schema,   
    // and for each data column create an output column and an external metadata column.  
    foreach (DataRow row in dataTable.Rows)  
    {  
        IDTSOutputColumn100 outColumn = output.OutputColumnCollection.New();  
        IDTSExternalMetadataColumn100 exColumn = output.ExternalMetadataColumnCollection.New();  

        // Set column data type properties.  
        bool isLong = false;  
        DataType dt = DataRecordTypeToBufferType((Type)row["DataType"]);  
        dt = ConvertBufferDataTypeToFitManaged(dt, ref isLong);  
        int length = 0;  
        int precision = (short)row["NumericPrecision"];  
        int scale = (short)row["NumericScale"];  
        int codepage = dataTable.Locale.TextInfo.ANSICodePage;  

        switch (dt)  
        {  
            // The length cannot be zero, and the code page property must contain a valid code page.  
            case DataType.DT_STR:  
            case DataType.DT_TEXT:  
                length = precision;  
                precision = 0;  
                scale = 0;  
                break;  

            case DataType.DT_WSTR:  
                length = precision;  
                codepage = 0;  
                scale = 0;  
                precision = 0;  
                break;  

            case DataType.DT_BYTES:  
                precision = 0;  
                scale = 0;  
                codepage = 0;  
                break;  

            case DataType.DT_NUMERIC:  
                length = 0;  
                codepage = 0;  

                if (precision > 38)  
                    precision = 38;  

                if (scale > 6)  
                    scale = 6;  
                break;  

            case DataType.DT_DECIMAL:  
                length = 0;  
                precision = 0;  
                codepage = 0;  
                break;  

            default:  
                length = 0;  
                precision = 0;  
                codepage = 0;  
                scale = 0;  
                break;  

        }  

        // Set the properties of the output column.  
        outColumn.Name = (string)row["ColumnName"];  
        outColumn.SetDataTypeProperties(dt, length, precision, scale, codepage);  
    }  
}  
Private sqlCommand As SqlCommand  

Private Sub CreateColumnsFromDataTable()  

    ' Get the output.  
    Dim output As IDTSOutput100 = ComponentMetaData.OutputCollection(0)  

    ' Start clean, and remove the columns from both collections.  
    output.OutputColumnCollection.RemoveAll()  
    output.ExternalMetadataColumnCollection.RemoveAll()  

    Me.sqlCommand = sqlConnection.CreateCommand()  
    Me.sqlCommand.CommandType = CommandType.Text  
    Me.sqlCommand.CommandText = CStr(ComponentMetaData.CustomPropertyCollection("SqlStatement").Value)  

    Dim schemaReader As SqlDataReader = Me.sqlCommand.ExecuteReader(CommandBehavior.SchemaOnly)  
    Dim dataTable As DataTable = schemaReader.GetSchemaTable()  

    ' Walk the columns in the schema,   
    ' and for each data column create an output column and an external metadata column.  
    For Each row As DataRow In dataTable.Rows  

        Dim outColumn As IDTSOutputColumn100 = output.OutputColumnCollection.New()  
        Dim exColumn As IDTSExternalMetadataColumn100 = output.ExternalMetadataColumnCollection.New()  

        ' Set column data type properties.  
        Dim isLong As Boolean = False  
        Dim dt As DataType = DataRecordTypeToBufferType(CType(row("DataType"), Type))  
        dt = ConvertBufferDataTypeToFitManaged(dt, isLong)  
        Dim length As Integer = 0  
        Dim precision As Integer = CType(row("NumericPrecision"), Short)  
        Dim scale As Integer = CType(row("NumericScale"), Short)  
        Dim codepage As Integer = dataTable.Locale.TextInfo.ANSICodePage  

        Select Case dt  

            ' The length cannot be zero, and the code page property must contain a valid code page.  
            Case DataType.DT_STR  
            Case DataType.DT_TEXT  
                length = precision  
                precision = 0  
                scale = 0  

            Case DataType.DT_WSTR  
                length = precision  
                codepage = 0  
                scale = 0  
                precision = 0  

            Case DataType.DT_BYTES  
                precision = 0  
                scale = 0  
                codepage = 0  

            Case DataType.DT_NUMERIC  
                length = 0  
                codepage = 0  

                If precision > 38 Then  
                    precision = 38  
                End If  

                If scale > 6 Then  
                    scale = 6  
                End If  

            Case DataType.DT_DECIMAL  
                length = 0  
                precision = 0  
                codepage = 0  

            Case Else  
                length = 0  
                precision = 0  
                codepage = 0  
                scale = 0  
        End Select  

        ' Set the properties of the output column.  
        outColumn.Name = CStr(row("ColumnName"))  
        outColumn.SetDataTypeProperties(dt, length, precision, scale, codepage)  
    Next  
End Sub  

구성 요소 유효성 검사Validating the Component

원본 구성 요소의 유효성을 검사하고 해당 출력 열 컬렉션에 정의된 열과 외부 데이터 원본에 있는 열이 일치하는지 확인해야 합니다.You should validate a source component and verify that the columns defined in its output column collections match the columns at the external data source. 때로는 연결이 끊어진 상태이거나 오랜 서버 왕복을 피하는 것이 바람직할 때와 같이 외부 데이터 원본을 기준으로 출력 열의 유효성을 검사하는 것이 불가능한 경우가 있습니다.Sometimes, verifying the output columns against the external data source can be impossible, such as in a disconnected state, or when it is preferable to avoid lengthy round trips to the server. 이러한 경우에도 출력 개체의 ExternalMetadataColumnCollection을 사용하여 출력의 열에 대한 유효성을 검사할 수 있습니다.In these situations, the columns in the output can still be validated by using the ExternalMetadataColumnCollection of the output object. 자세한 내용은 참조 유효성을 검사 하는 데이터 흐름 구성 요소합니다.For more information, see Validating a Data Flow Component.

이 컬렉션은 입력 개체와 출력 개체 모두에 있으며 외부 데이터 원본의 열로 이 컬렉션을 채울 수 있습니다.This collection exists on both input and output objects and you can populate it with the columns from the external data source. 이 컬렉션을 사용 하 여 출력 열의 유효성을 검사할 수 있습니다 때 SSISSSIS 디자이너는 오프 라인 구성 요소는 연결이 끊어졌기 때나 때는 ValidateExternalMetadata 속성은 false합니다.You can use this collection to validate the output columns when SSISSSIS Designer is offline, when the component is disconnected, or when the ValidateExternalMetadata property is false. 먼저 출력 열이 만들어짐과 동시에 컬렉션이 채워져 있어야 합니다.The collection should be first populated at the same time that the output columns are created. 외부 메타데이터 열은 처음에는 출력 열과 일치하므로 컬렉션에 외부 메타데이터 열을 추가하는 것은 비교적 쉽습니다.Adding external metadata columns to the collection is relatively easy because the external metadata column should initially match the output column. 열의 데이터 형식 속성은 이미 올바르게 설정되어 있어야 하며 이 속성을 IDTSExternalMetadataColumn100 개체에 직접 복사할 수 있습니다.The data type properties of the column should have already been set correctly, and the properties can be copied directly to the IDTSExternalMetadataColumn100 object.

다음 예제 코드에서는 새로 만들어진 출력 열을 기반으로 외부 메타데이터 열을 추가합니다.The following sample code adds an external metadata column that is based on a newly created output column. 출력 열은 이미 만들어진 것으로 가정합니다.It assumes that the output column has already been created.

private void CreateExternalMetaDataColumn(IDTSOutput100 output, IDTSOutputColumn100 outputColumn)  
{  

    // Set the properties of the external metadata column.  
    IDTSExternalMetadataColumn100 externalColumn = output.ExternalMetadataColumnCollection.New();  
    externalColumn.Name = outputColumn.Name;  
    externalColumn.Precision = outputColumn.Precision;  
    externalColumn.Length = outputColumn.Length;  
    externalColumn.DataType = outputColumn.DataType;  
    externalColumn.Scale = outputColumn.Scale;  

    // Map the external column to the output column.  
    outputColumn.ExternalMetadataColumnID = externalColumn.ID;  

}  
Private Sub CreateExternalMetaDataColumn(ByVal output As IDTSOutput100, ByVal outputColumn As IDTSOutputColumn100)  

        ' Set the properties of the external metadata column.  
        Dim externalColumn As IDTSExternalMetadataColumn100 = output.ExternalMetadataColumnCollection.New()  
        externalColumn.Name = outputColumn.Name  
        externalColumn.Precision = outputColumn.Precision  
        externalColumn.Length = outputColumn.Length  
        externalColumn.DataType = outputColumn.DataType  
        externalColumn.Scale = outputColumn.Scale  

        ' Map the external column to the output column.  
        outputColumn.ExternalMetadataColumnID = externalColumn.ID  

    End Sub  

런타임Run Time

실행 중 구성 요소는 데이터 흐름 태스크에서 만들어 PrimeOutput을 통해 구성 요소에 제공한 출력 버퍼에 행을 추가합니다.During execution, components add rows to output buffers that are created by the data flow task and provided to the component in PrimeOutput. 원본 구성 요소에 대해 이 메서드가 호출되고 나면 이 메서드는 다운스트림 구성 요소에 연결된 구성 요소의 각 IDTSOutput100에 대한 출력 버퍼를 받습니다.Called once for source components, the method receives an output buffer for each IDTSOutput100 of the component that is connected to a downstream component.

버퍼에서 열 찾기Locating Columns in the Buffer

구성 요소의 출력 버퍼에는 해당 구성 요소에서 정의한 열과 다운스트림 구성 요소의 출력에 추가된 열이 들어 있습니다.The output buffer for a component contains the columns defined by the component and any columns added to the output of a downstream component. 예를 들어 원본 구성 요소에서 출력에 세 개의 열을 제공하고 다음 구성 요소에서 네 번째 출력 열을 하나 추가할 경우, 원본 구성 요소에서 사용하도록 제공된 출력 버퍼에는 이 네 개의 열이 포함됩니다.For example, if a source component provides three columns in its output, and the next component adds a fourth output column, the output buffer provided for use by the source component contains these four columns.

버퍼 행의 열 순서는 출력 열 컬렉션에 있는 출력 열의 인덱스로 정의되지 않습니다.The order of the columns in a buffer row is not defined by the index of the output column in the output column collection. 따라서 FindColumnByLineageIDBufferManager 메서드를 사용해야 버퍼 행에서 출력 열을 정확하게 찾을 수 있습니다.An output column can only be accurately located in a buffer row by using the FindColumnByLineageID method of the BufferManager. 이 메서드는 지정된 버퍼에서 지정된 계보 ID가 있는 열을 찾고 해당 위치를 행에 반환합니다.This method locates the column with the specified lineage ID in the specified buffer, and returns its location in the row. 출력 열의 인덱스는 일반적으로 PreExecute 메서드 실행 중에 검색되며 PrimeOutput 실행 중에 사용할 수 있도록 저장됩니다.The indexes of the output columns are typically located in the PreExecute method, and stored for use during PrimeOutput.

다음 코드 예에서는 PreExecute를 호출하는 중에 출력 버퍼에서 출력 열의 위치를 찾고 이를 내부 구조에 저장합니다.The following code example finds the location of the output columns in the output buffer during a call to PreExecute, and stores them in an internal structure. 열의 이름도 구조에 저장되며 이 이름은 이 항목의 다음 섹션에서 PrimeOutput 메서드에 대한 코드 예에 사용됩니다.The name of the column is also stored in the structure and is used in the code example for the PrimeOutput method in the next section of this topic.

ArrayList columnInformation;  

private struct ColumnInfo  
{  
    public int BufferColumnIndex;  
    public string ColumnName;  
}  

public override void PreExecute()  
{  
    this.columnInformation = new ArrayList();  
    IDTSOutput100 output = ComponentMetaData.OutputCollection[0];  

    foreach (IDTSOutputColumn100 col in output.OutputColumnCollection)  
    {  
        ColumnInfo ci = new ColumnInfo();  
        ci.BufferColumnIndex = BufferManager.FindColumnByLineageID(output.Buffer, col.LineageID);  
        ci.ColumnName = col.Name;  
        columnInformation.Add(ci);  
    }  
}  
Public Overrides Sub PreExecute()  

    Me.columnInformation = New ArrayList()  
    Dim output As IDTSOutput100 = ComponentMetaData.OutputCollection(0)  

    For Each col As IDTSOutputColumn100 In output.OutputColumnCollection  

        Dim ci As ColumnInfo = New ColumnInfo()  
        ci.BufferColumnIndex = BufferManager.FindColumnByLineageID(output.Buffer, col.LineageID)  
        ci.ColumnName = col.Name  
        columnInformation.Add(ci)  
    Next  
End Sub  

행 처리Processing Rows

AddRow 메서드를 호출하여 출력 버퍼에 행을 추가하면 열에 빈 값이 있는 새 버퍼 행이 만들어집니다.Rows are added to the output buffer by calling the AddRow method, which creates a new buffer row with empty values in its columns. 그런 다음 구성 요소에서는 개별 열에 값을 할당합니다.The component then assigns values to the individual columns. 구성 요소에 제공된 출력 버퍼는 데이터 흐름 태스크에서 만들어지고 모니터링됩니다.The output buffers provided to a component are created and monitored by the data flow task. 출력 버퍼가 가득 차면 버퍼의 행은 다음 구성 요소로 이동됩니다.As they become full, the rows in the buffer are moved to the next component. 데이터 흐름 태스크에 의한 행 이동은 구성 요소 개발자가 인식할 수 있으며 RowCount 속성은 출력 버퍼에서 항상 0으로 설정되므로 행 일괄 처리가 다음 구성 요소로 보내졌는지 확인할 수 있는 방법은 없습니다.There is no way to determine when a batch of rows has been sent to the next component because the movement of rows by the data flow task is transparent to the component developer, and the RowCount property is always zero on output buffers. 출력 버퍼에 행을 모두 추가한 경우 원본 구성 요소에서는 SetEndOfRowsetPipelineBuffer 메서드를 호출하여 이를 데이터 흐름 태스크에 알리며 버퍼의 나머지 행은 다음 구성 요소에 전달됩니다.When a source component is finished adding rows to its output buffer, it notifies the data flow task by calling the SetEndOfRowset method of the PipelineBuffer, and the remaining rows in the buffer are passed to the next component.

원본 구성 요소에서 외부 데이터 원본의 행을 읽는 동안 IncrementPipelinePerfCounter 메서드를 호출하여 "Rows read" 또는 "BLOB bytes read" 성능 카운터를 업데이트할 수 있습니다.While the source component reads rows from the external data source, you may want to update the "Rows read" or "BLOB bytes read" performance counters by calling the IncrementPipelinePerfCounter method. 자세한 내용은 성능 카운터를 참조하세요.For more information, see Performance Counters.

다음 코드 예에서는 PrimeOutput에서 출력 버퍼에 행을 추가하는 구성 요소를 보여 줍니다.The following code example shows a component that adds rows to an output buffer in PrimeOutput. 버퍼에 있는 출력 열의 인덱스는 위의 코드 예에서 PreExecute 사용 중 찾은 것입니다.The indexes of the output columns in the buffer were located using PreExecute in the previous code example.

public override void PrimeOutput(int outputs, int[] outputIDs, PipelineBuffer[] buffers)  
{  
    IDTSOutput100 output = ComponentMetaData.OutputCollection[0];  
    PipelineBuffer buffer = buffers[0];  

    SqlDataReader dataReader = sqlCommand.ExecuteReader();  

    // Loop over the rows in the DataReader,   
    // and add them to the output buffer.  
    while (dataReader.Read())  
    {  
        // Add a row to the output buffer.  
        buffer.AddRow();  

        for (int x = 0; x < columnInformation.Count; x++)  
        {  
            ColumnInfo ci = (ColumnInfo)columnInformation[x];  
            int ordinal = dataReader.GetOrdinal(ci.ColumnName);  

            if (dataReader.IsDBNull(ordinal))  
                buffer.SetNull(ci.BufferColumnIndex);  
            else  
            {  
                buffer[ci.BufferColumnIndex] = dataReader[ci.ColumnName];  
            }  
        }  
    }  
    buffer.SetEndOfRowset();  
}  
Public Overrides Sub PrimeOutput(ByVal outputs As Integer, ByVal outputIDs As Integer(), ByVal buffers As PipelineBuffer())  

    Dim output As IDTSOutput100 = ComponentMetaData.OutputCollection(0)  
    Dim buffer As PipelineBuffer = buffers(0)  

    Dim dataReader As SqlDataReader = sqlCommand.ExecuteReader()  

    ' Loop over the rows in the DataReader,   
    ' and add them to the output buffer.  
    While (dataReader.Read())  

        ' Add a row to the output buffer.  
        buffer.AddRow()  

        For x As Integer = 0 To columnInformation.Count  

            Dim ci As ColumnInfo = CType(columnInformation(x), ColumnInfo)  

            Dim ordinal As Integer = dataReader.GetOrdinal(ci.ColumnName)  

            If (dataReader.IsDBNull(ordinal)) Then  
                buffer.SetNull(ci.BufferColumnIndex)  
            Else  
                buffer(ci.BufferColumnIndex) = dataReader(ci.ColumnName)  

            End If  
        Next  

    End While  

    buffer.SetEndOfRowset()  
End Sub  

예제Sample

다음 예제에서는 파일 연결 관리자를 사용하여 파일의 이진 내용을 데이터 흐름으로 로드하는 간단한 원본 구성 요소를 보여 줍니다.The following sample shows a simple source component that uses a File connection manager to load the binary contents of files into the data flow. 이 예제는 이 항목에 설명된 메서드 및 기능의 일부를 보여 줍니다.This sample does not demonstrate all the methods and functionality discussed in this topic. 또한 모든 사용자 지정 원본 구성 요소에서 재정의해야 하는 중요한 메서드를 보여 주지만 디자인 타임 유효성 검사를 위한 코드는 포함하지 않습니다.It demonstrates the important methods that every custom source component must override, but does not contain code for design-time validation.

using System;  
using System.IO;  
using Microsoft.SqlServer.Dts.Pipeline;  
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;  
using Microsoft.SqlServer.Dts.Runtime.Wrapper;  

namespace BlobSrc  
{  
  [DtsPipelineComponent(DisplayName = "BLOB Inserter Source", Description = "Inserts files into the data flow as BLOBs")]  
  public class BlobSrc : PipelineComponent  
  {  
    IDTSConnectionManager100 m_ConnMgr;  
    int m_FileNameColumnIndex = -1;  
    int m_FileBlobColumnIndex = -1;  

    public override void ProvideComponentProperties()  
    {  
      IDTSOutput100 output = ComponentMetaData.OutputCollection.New();  
      output.Name = "BLOB File Inserter Output";  

      IDTSOutputColumn100 column = output.OutputColumnCollection.New();  
      column.Name = "FileName";  
      column.SetDataTypeProperties(DataType.DT_WSTR, 256, 0, 0, 0);  

      column = output.OutputColumnCollection.New();  
      column.Name = "FileBLOB";  
      column.SetDataTypeProperties(DataType.DT_IMAGE, 0, 0, 0, 0);  

      IDTSRuntimeConnection100 conn = ComponentMetaData.RuntimeConnectionCollection.New();  
      conn.Name = "FileConnection";  
    }  

    public override void AcquireConnections(object transaction)  
    {  
      IDTSRuntimeConnection100 conn = ComponentMetaData.RuntimeConnectionCollection[0];  
      m_ConnMgr = conn.ConnectionManager;  
    }  

    public override void ReleaseConnections()  
    {  
      m_ConnMgr = null;  
    }  

    public override void PreExecute()  
    {  
      IDTSOutput100 output = ComponentMetaData.OutputCollection[0];  

      m_FileNameColumnIndex = (int)BufferManager.FindColumnByLineageID(output.Buffer, output.OutputColumnCollection[0].LineageID);  
      m_FileBlobColumnIndex = (int)BufferManager.FindColumnByLineageID(output.Buffer, output.OutputColumnCollection[1].LineageID);  
    }  

    public override void PrimeOutput(int outputs, int[] outputIDs, PipelineBuffer[] buffers)  
    {  
      string strFileName = (string)m_ConnMgr.AcquireConnection(null);  

      while (strFileName != null)  
      {  
        buffers[0].AddRow();  

        buffers[0].SetString(m_FileNameColumnIndex, strFileName);  

        FileInfo fileInfo = new FileInfo(strFileName);  
        byte[] fileData = new byte[fileInfo.Length];  
        FileStream fs = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.Read);  
        fs.Read(fileData, 0, fileData.Length);  

        buffers[0].AddBlobData(m_FileBlobColumnIndex, fileData);  

        strFileName = (string)m_ConnMgr.AcquireConnection(null);  
      }  

      buffers[0].SetEndOfRowset();  
    }  
  }  
}  
Imports System   
Imports System.IO   
Imports Microsoft.SqlServer.Dts.Pipeline   
Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper   
Imports Microsoft.SqlServer.Dts.Runtime.Wrapper   
Namespace BlobSrc   

 <DtsPipelineComponent(DisplayName="BLOB Inserter Source", Description="Inserts files into the data flow as BLOBs")> _   
 Public Class BlobSrc   
 Inherits PipelineComponent   
   Private m_ConnMgr As IDTSConnectionManager100   
   Private m_FileNameColumnIndex As Integer = -1   
   Private m_FileBlobColumnIndex As Integer = -1   

   Public  Overrides Sub ProvideComponentProperties()   
     Dim output As IDTSOutput100 = ComponentMetaData.OutputCollection.New   
     output.Name = "BLOB File Inserter Output"   
     Dim column As IDTSOutputColumn100 = output.OutputColumnCollection.New   
     column.Name = "FileName"   
     column.SetDataTypeProperties(DataType.DT_WSTR, 256, 0, 0, 0)   
     column = output.OutputColumnCollection.New   
     column.Name = "FileBLOB"   
     column.SetDataTypeProperties(DataType.DT_IMAGE, 0, 0, 0, 0)   
     Dim conn As IDTSRuntimeConnection90 = ComponentMetaData.RuntimeConnectionCollection.New   
     conn.Name = "FileConnection"   
   End Sub   

   Public  Overrides Sub AcquireConnections(ByVal transaction As Object)   
     Dim conn As IDTSRuntimeConnection100 = ComponentMetaData.RuntimeConnectionCollection(0)   
     m_ConnMgr = conn.ConnectionManager   
   End Sub   

   Public  Overrides Sub ReleaseConnections()   
     m_ConnMgr = Nothing   
   End Sub   

   Public  Overrides Sub PreExecute()   
     Dim output As IDTSOutput100 = ComponentMetaData.OutputCollection(0)   
     m_FileNameColumnIndex = CType(BufferManager.FindColumnByLineageID(output.Buffer, output.OutputColumnCollection(0).LineageID), Integer)   
     m_FileBlobColumnIndex = CType(BufferManager.FindColumnByLineageID(output.Buffer, output.OutputColumnCollection(1).LineageID), Integer)   
   End Sub   

   Public  Overrides Sub PrimeOutput(ByVal outputs As Integer, ByVal outputIDs As Integer(), ByVal buffers As PipelineBuffer())   
     Dim strFileName As String = CType(m_ConnMgr.AcquireConnection(Nothing), String)   
     While Not (strFileName Is Nothing)   
       buffers(0).AddRow   
       buffers(0).SetString(m_FileNameColumnIndex, strFileName)   
       Dim fileInfo As FileInfo = New FileInfo(strFileName)   
       Dim fileData(fileInfo.Length) As Byte   
       Dim fs As FileStream = New FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.Read)   
       fs.Read(fileData, 0, fileData.Length)   
       buffers(0).AddBlobData(m_FileBlobColumnIndex, fileData)   
       strFileName = CType(m_ConnMgr.AcquireConnection(Nothing), String)   
     End While   
     buffers(0).SetEndOfRowset   
   End Sub   
 End Class   
End Namespace  

관련 항목:See Also

사용자 지정 대상 구성 요소 개발 Developing a Custom Destination Component
스크립트 구성 요소를 사용 하 여 원본 만들기Creating a Source with the Script Component