2016-12-08 5 views
1

MSDN [https://social.msdn.microsoft.com/Forums/en-US/6cd447d8-21e5-44be-aee6-ad6bdcaac40f/programmatically-created-package-having-difficulties-running?forum=sqlintegrationservices]]에 동일한 질문을 게시했으며 여기에있는 사람이 도움을 얻을 수 있기를 바랍니다.SSIS 프로그래밍 패키지 유효성 확인/실행

--- 여기에 질문 ---

내가 오라클 테이블 ([NUM]라는 하나 개의 INT 컬럼) SQL Server 테이블에서 데이터를로드하는 간단한 SSIS 작업을 만들기 위해 노력하고는 (와의 SSIS 용 .NET Interop 어셈블리를 통해 [ID]라는 하나의 NUMBER 열). 패키지를 만들고 DTSX 파일에 저장할 수 있지만 프로그래밍 방식으로 또는 dtexec을 통해 실행하면 실패합니다. 프로그래밍 방식으로 패키지를 만드는 데 대한 dev 가이드를 따르고 있습니다. 다양한 오브젝트의 속성을 살펴보면 나에게 아무 것도 나타나지 않습니다.

2 차적인 문제로, 사용 가능한 Package.Validate 메서드가있는 것을 볼 수 있지만이를 호출하는 방법을 알지 못합니다 (인수와 반환 값이 필요합니다). dtexec을 통해 패키지를 실행할 때 유효성 검사를 수행하고 다소 유용한 유효성 검사 오류를 제공하므로 프로그래밍 방식으로 연결할 수 있기를 바랍니다.

내가 얻는 유효성 검사 오류는 다음과 같습니다

나는 온라인으로 무엇을 말할 수에서

Error: 2016-12-08 09:39:15.96 Code: 0xC004706B Source: {A8E8D1A6-3826-4222-B6DC-46008A1722DF} SSIS.Pipeline Description: "OLE DB Destination" failed validation and returned validation status "VS_NEEDSNEWMETADATA".

,이 오류의 원인은 나쁜 열 매핑이다, 그러나 나는 dev에 가이드에서 더 많거나 적은 바로 코드를 해제했습니다 .

그래서 내 두 가지 질문은 다음과 같습니다

  1. 어떻게이 유효성 검사 오류 VS_NEEDSNEWMETADATA, 바람직하게는 프로그래밍 방식으로 문제를 해결할 수 있습니다?
  2. 어떻게 프로그래밍 방식으로 이러한 유효성 검사 오류를 얻기 위해 Package.Validate를 호출 할 수 있습니다? **

어떤 도움에 감사드립니다!

목록 전체 코드 (I 비주얼 스튜디오를 사용하여 C# 대화에서 이것을 실행, 예외가 발생되지하지만 결과는 실패의 값으로 끝나는된다) :

// these are just adding references to the context: 
#r "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SqlServer.DTSPipelineWrap\v4.0_11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.DTSPipelineWrap.dll" 
#r "C:\Windows\Microsoft.NET\assembly\GAC_64\Microsoft.SqlServer.DTSRuntimeWrap\v4.0_11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.DTSRuntimeWrap.dll" 
#r "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SqlServer.ManagedDTS\v4.0_11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.ManagedDTS.dll" 
#r "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\Microsoft.SqlServer.PipelineHost\v4.0_11.0.0.0__89845dcd8080cc91\Microsoft.SqlServer.PipelineHost.dll" 
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.dll" 
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Core.dll" 
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Xml.Linq.dll" 
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.DataSetExtensions.dll" 
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\Microsoft.CSharp.dll" 
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dll" 
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Net.Http.dll" 
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Xml.dll" 
// the actual code: 

using dtsrt = Microsoft.SqlServer.Dts.Runtime; 
using dtsp = Microsoft.SqlServer.Dts.Pipeline; 
using dtspw = Microsoft.SqlServer.Dts.Pipeline.Wrapper; 
using refl = System.Reflection; 
private string GetHresultSymbolicName(int errorCode) 
{ 
    dtsrt.HResults hresults = new Microsoft.SqlServer.Dts.Runtime.HResults(); 
    return (from refl.FieldInfo fi in hresults.GetType().GetFields() where (((int)fi.GetValue(hresults)) == errorCode) select fi.Name).Single(); 
} 

// base setup 
dtsrt.Package package = new dtsrt.Package(); 
dtsrt.Executable e = package.Executables.Add("STOCK:PipelineTask"); 
dtsrt.TaskHost thMainPipe = e as dtsrt.TaskHost; 
dtspw.MainPipe dataFlowTask = thMainPipe.InnerObject as dtspw.MainPipe; 
dtsrt.Application app = new Microsoft.SqlServer.Dts.Runtime.Application(); 
dtsrt.PipelineComponentInfos componentInfos = app.PipelineComponentInfos; 

// source connection 
dtsrt.ConnectionManager srcConnectionManager = package.Connections.Add("OLEDB"); 
srcConnectionManager.Name = "Source OLEDB Connection"; 
srcConnectionManager.ConnectionString = "Provider=SQLOLEDB; Address=XXX; Database=Sandbox; Trusted_Connection=yes;"; 

// dest connection 
dtsrt.ConnectionManager destConnectionManager = package.Connections.Add("OLEDB"); 
destConnectionManager.Name = "Destination OLEDB Connection"; 
destConnectionManager.ConnectionString = "Provider=OraOLEDB.Oracle; Data Source=XXX;User Id=SANDBOX;Password=123456;"; 
// thanks: ole.OleDbDataReader rdr = ole.OleDbEnumerator.GetRootEnumerator(); 

// dest component 
dtspw.IDTSComponentMetaData100 destComponent = dataFlowTask.ComponentMetaDataCollection.New(); 
destComponent.ComponentClassID = "DTSAdapter.OLEDBDestination.3"; 
destComponent.Instantiate(); 
dtspw.CManagedComponentWrapper destWrapper = destComponent.Instantiate(); 
destWrapper.ProvideComponentProperties(); 
destComponent.RuntimeConnectionCollection[0].ConnectionManager = dtsrt.DtsConvert.GetExtendedInterface(destConnectionManager); 
destComponent.RuntimeConnectionCollection[0].ConnectionManagerID = destConnectionManager.ID; 
destComponent.CustomPropertyCollection["CommandTimeout"].Value = 0; // no timeout 
destComponent.CustomPropertyCollection["AccessMode"].Value = 2; // sqlcommand 
destComponent.CustomPropertyCollection["SqlCommand"].Value = "select * from my_asdf"; 
destWrapper.AcquireConnections(null); 
destWrapper.ReinitializeMetaData(); 
destWrapper.ReleaseConnections(); 

// source component 
dtspw.IDTSComponentMetaData100 srcComponent = dataFlowTask.ComponentMetaDataCollection.New(); 
srcComponent.ComponentClassID = "DTSAdapter.OLEDBSource.3"; 
srcComponent.Instantiate(); 
dtspw.CManagedComponentWrapper srcWrapper = srcComponent.Instantiate(); 
srcWrapper.ProvideComponentProperties(); 
srcComponent.RuntimeConnectionCollection[0].ConnectionManager = dtsrt.DtsConvert.GetExtendedInterface(srcConnectionManager); 
srcComponent.RuntimeConnectionCollection[0].ConnectionManagerID = srcConnectionManager.ID; 
srcComponent.CustomPropertyCollection["CommandTimeout"].Value = 0; // no timeout 
srcComponent.CustomPropertyCollection["AccessMode"].Value = 2; // sqlcommand 
srcComponent.CustomPropertyCollection["SqlCommand"].Value = "select num from big_numbers2"; 
srcWrapper.AcquireConnections(null); 
srcWrapper.ReinitializeMetaData(); 
srcWrapper.ReleaseConnections(); 

dtspw.IDTSPath100 path = dataFlowTask.PathCollection.New(); 
path.AttachPathAndPropagateNotifications(srcComponent.OutputCollection[0], destComponent.InputCollection[0]); 

// Just one column mapping, as each table has just one column 
dtspw.IDTSInput100 destInput = destComponent.InputCollection[0]; 
dtspw.IDTSVirtualInput100 vDestInput = destInput.GetVirtualInput(); 
destWrapper.SetUsageType(destInput.ID, vDestInput, vDestInput.VirtualInputColumnCollection[0].LineageID, dtspw.DTSUsageType.UT_READONLY); 

// save it, run it 
app.SaveToXml("D:\\myDtsx.dtsx", package, null); 
dtsrt.DTSExecResult result = package.Execute(); // result = failure 

답변

0

내가 코드보고에서 생각입니다 ... 당신이 당신의 문제를 해결하는 데 도움이 : 즉, 당신이 입력 사이의 연결을 확인하기 위해 단계를 누락 생각 열 및 대상 열의 외부 열.

대상 구성 요소의 경우 SqlCommand를 할당 한 후 다음 코드 세 줄 (AcquireConn, Reinit Meta 및 Close Conn)은 본질적으로 oracle 데이터베이스에서 sql 명령의 메타 데이터를 가져옵니다. 이 메타는 열의 이름과 관련 데이터 유형이됩니다. 이 정보는 대상 구성 요소의 ExternalMetadataColumn 컬렉션에 저장됩니다. 이제 대상 구성 요소에서 ExternalMetadataColumn 컬렉션의 열이 대상 구성 요소의 InputColumn 컬렉션에있는 열과 연결될 때 "열 매핑"이 설정됩니다.

코드에서 대상 구성 요소에서 메타 데이터 호출을 한 후에 원본 구성 요소를 만듭니다. 따라서 대상 구성 요소의 외부 메타 데이터가 만들어지면 외부 메타 데이터 열을 연결할 입력 열이 없습니다.

소스 구성 요소를 만든 후 GetVirtualInput을 호출하는 소스와 대상을 연결 한 다음 UT_READONLY를 사용하여 SetUsageType을 호출하면 코드가 더 아래로 내려갑니다. UT_READONLY를 사용하여 SetUsageType을 호출 한 후에는 대상 구성 요소에서 사용할 수있는 입력 열을 가져온 다음 외부 메타 데이터 열과 연결할 수 있습니다.

SetUsageType을 호출 한 후 이제 대상 디자인 타임 구성 요소에서 MapInputColumn 메서드를 호출하고 일치시킬 입력, 입력 열 및 외부 메타 데이터 열의 ID를 전달합니다.

그래서 당신은 "my_external_column"라는 외부 열 소스 기기에서 "NUM"열을 매핑 할 가정, 당신은이 작업을 수행 woudl :

IDTSInputColumn100 inputColumn = destInputCols.InputColumnCollection["num"]; 

IDTSExternalMetadataColumn100 externalColumn = destInput.ExternalMetadataColumnCollection["my_external_column"]; 

destWrapper.MapInputColumn(destInput.ID, inputColumn.ID, externalColumn.ID) 

당신은 열을 볼 수 있어야합니다 "올바르게"매핑됩니다. 매핑이 성공하려면 데이터 형식 (특히 SSIS 데이터 형식)이 일치해야합니다.

+0

코드의 첫 번째 줄에서 destInput.InputColumnCollection을 의미한다고 가정합니다. 그게 분명히 효과가 있었기 때문에! 이 답변을 표시하고 있지만, 내가 배운 방식을 확장 할 수 있다면 감사히 여길 것입니다. 나는 MSDN의 문서를 읽었으며, 그들은 희소하고 파악하기 힘들거나 밀도가 높다. 정말 알고 싶다. –

+0

예. 코드의 첫 번째 줄에는 destInput이 사용됩니다. –

+0

학습만큼, 대부분 문서화를 통해 코딩하고 dtsx의 XML에서 변경 사항을 관찰하는 것이 었습니다. 조만간 모든 파이프 라인 구성 요소 (조회 또는 병합 또는 소스 등)가 구성되는 것과 동일한 설계 원칙을 따름을 알게 될 것입니다. 이것에 몇 가지 메모를 합쳐서 알려 드리겠습니다. 한편, 다른 프로그래밍 방식의 질문이 있으면 알려주십시오. –

0

당신의에 .dtsx 파일을 여는 시도 되세요 텍스트 편집기를 사용하여 패키지의 메타 데이터 정보를 검토하십시오. 뭐라구?

의심되는 점은 SQL Server 쿼리의 "선택 *"이 올바른 데이터 형식으로 해석되지 않는다는 것입니다. 오류는 대상 열에 일치하는 유효한 데이터 형식이 아니므로 대상에 입력 될 때까지 표시되지 않습니다. 실수가 아닌 경우 오류가 표시됩니다.

Oracle NUMBER도 INT와 완전히 동일하지 않습니다. 이 가이드에서 SQL Server와 Oracle간에 데이터 형식 변환 작업을 수행하기 위해 패키지에 단계를 추가 할 필요가 없는지 확인하십시오. http://docs.oracle.com/cd/B19306_01/gateways.102/b14270/apa.htm

희망이 두 가지 중 하나는

여기
+0

"선택 *"은 Oracle (대상) 쿼리에 포함되어 있으며 SSIS에 분명히 만족합니다. 나는 그것이 이상하게 보인 것에 동의한다. NUMBER 대 INT 비즈니스는 내 마음을 넘어 섰지 만 NUMBER는 INT 값을받습니다. 그래서 나는 그것이 괜찮을 것이라고 결정했습니다 (본질적으로 하위 집합 임). SSIS는 분명히 동의합니다. 어쨌든 고마워. :) –