上一篇講到了同步轉換和非同步轉換的概念。通常情況下,大部分轉換都是同步的,即收到一行就處理一行。(注意,這樣說可能不是很準確,實際上即便是同步機制,資料流也會適當的進行緩衝的,只不過這種緩衝對使用者數透明的,使用者可以理解為收到一行就處理一行)
同步轉換組件可以很簡單,也可以很複雜。這取決於你的設計邏輯。
這一篇我還是用一個簡單的例子來講解,旨在讓大家瞭解同步轉換組件的設計流程。
需求:我們這個組件很簡單,就是將輸入列中的文本列的所有字母全部轉換為大寫。
1. 準備一個類型
[DtsPipelineComponent(
ComponentType=ComponentType.Transform,
Description="這是我的一個自訂資料轉換"
,
DisplayName="大寫轉換"
)]
public
class
MyTransfomation:PipelineComponent
{
}
這個類型是我們上次準備好的,但沒有做實現。【注意】我把DisplayName改成了“大寫轉換”
如果你是從頭開始做,那麼請注意,添加以下的引用和using語句
2. 實現代碼
代碼將由幾個部分組成
首先仍然是 ProvideComponentProperties方法,這個方法準備一些中繼資料。一般都是定義輸入和輸出的屬性。該方法的佔位代碼如下
public
override
void
ProvideComponentProperties()
{
base
.ProvideComponentProperties();
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
我們對其加以修改。我們需要知道的一個基礎知識就是:任何一個轉換,即便不做任何事情,它也自動具有一個預設的輸入和輸出。
我們在這個代碼裡面給預設的輸入和輸出做一個重新命名。這樣做的目的是讓它們更加形象
/// <summary>
/// 這個方法提供組件必須的一些屬性。
/// 這裡主要給預設的輸入和輸出重新命名,讓它更加形象
/// </summary>
public
override
void
ProvideComponentProperties()
{
base
.ProvideComponentProperties();
ComponentMetaData.InputCollection[0].Name = "大寫轉換輸入"
;
ComponentMetaData.OutputCollection[0].Name = "大寫轉換輸出"
;
//ComponentMetaData.OutputCollection[1].SynchronousInputID = ComponentMetaData.InputCollection[0].ID;
//如果調用了base.ProvideComponentProperties,則可以省略這句代碼
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
第二步:我們重寫PreExecute方法,這個方法為執行做準備。我們這裡的需求比較簡單,就是檢查所有最終確定的輸入列,如果他們的類型是字元型(不管是STR還是WSTR),我們就對它們做一個記號
List<int
> _columns = new
List<int
>();//這個集合來儲存需要處理的列的索引號
/// <summary>
/// 這個方法是ProcessInput之前的準備工作。
/// 我們檢測所有輸入列中類型為字元型的,並將它的索引號記錄起來
/// 為了讓ProcessInput能使用到這個資訊,我們定義一個公用變數
/// </summary>
public
override
void
PreExecute()
{
IDTSInput90 input = ComponentMetaData.InputCollection[0];
IDTSInputColumnCollection90 columns = input.InputColumnCollection;
foreach
(IDTSInputColumn90 item in
columns)
{
if
(item.DataType == DataType.DT_WSTR || item.DataType == DataType.DT_STR)
{
_columns.Add(BufferManager.FindColumnByLineageID(input.Buffer, item.LineageID));
}
}
}
第三步:我們重寫ProcessInput方法。這個方法會被資料流程工作多次調用。我們就是不斷地進行處理,直到資料來源不再能提供資料為止。
public
override
void
ProcessInput(int
inputID, PipelineBuffer buffer)
{
while
(buffer.NextRow())//從這句話可以理解,其實雖然說是同步,但也可能是緩衝了幾行後才處理,而不一定是一行處理一次
{
foreach
(int
index in
_columns)
{
string
str = buffer.GetString(index);
buffer.SetString(index, str.ToUpper());
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
我們這裡只是對輸入的buffer進行處理。注意,這裡很有意思的是,我們其實很簡單的,先把buffer中某個列的值讀出來,然後將其轉回大寫之後寫回去即可。
3. 重新編譯項目,部署。在BI Studio中進行測試
我們只需要勾選上有關的輸入列即可。其他不需要任何的設定
現在就可以執行任務了。如果不出意外,任務能夠成功執行,如所示
我們最後開啟產生的那個文字檔進行驗證
我們看到,第一列和第三列的文本全部被處理成了大寫。
我們也可以在資料流中添加“查看器”,很清楚的看到從“檔案夾資料來源”到“大寫轉換”這個管道中,字元是小寫
而在“大寫轉換”到“一般檔案目標”這個管道中,字元就被轉變為大寫了
補充:
該轉換組件已經可以工作了。但我們還是可以添加下面的一些功能(例如驗證),以便讓它更加完整
public
override
DTSValidationStatus Validate()
{
//驗證組件,至少要有一個輸入列
IDTSInput90 input = ComponentMetaData.InputCollection[0];
if
(input.InputColumnCollection.Count > 0)
return
DTSValidationStatus.VS_ISVALID;
ComponentMetaData.FireWarning(0,
ComponentMetaData.Name,
"至少應該選擇一個輸入列"
,
string
.Empty,
0);
return
DTSValidationStatus.VS_ISBROKEN;
}
public
override
void
DeleteInput(int
inputID)
{
throw
new
Exception("不能刪除輸入"
);
}
public
override
IDTSCustomProperty90 SetInputProperty(int
inputID,
string
propertyName, object
propertyValue)
{
throw
new
Exception("不能修改輸入"
);
}
這樣的話,如果使用者沒有選擇列,則會出現下面的錯誤