在提供者之間轉換資料
在許多應用程式中,所有提供者都會使用相同的格式同步處理完全相同的資料類型。例如,幾個資料庫同步處理提供者可能會針對 ADO.NET 資料集中的一組資料表同步處理及傳輸資料。但是,資料格式在某些情況下可能會不同。假設有一個應用程式會同步處理連絡人。此應用程式使用兩個不同的開發人員所撰寫的自訂提供者。這些提供者所需要的資料在兩個方面有所不同:
提供者 A 將資料當做位元組資料流傳輸,而提供者 B 將資料當做 XML 資料流傳輸。
提供者 A 的資料是由三個欄位所組成:FirstName、LastName 和 PhoneNumber。提供者 B 的資料包括 FirstName 和 LastName,並將 PhoneNumber 分成 PhoneNumber 和 AreaCode。
為了處理這個情況,Sync Framework 會讓您實作介面,將資料轉換成每個提供者所需要的格式。在此情況下,您會撰寫轉換器來執行兩個轉換:第一個會將位元組資料流輸入轉換成 XML 輸出,第二個會將 XML 輸入轉換成位元組資料流輸出。Sync Framework 不會要求兩個提供者都要指定轉換器。您所實作的資料轉換程式碼是由同步處理工作階段所呼叫,如此一來,變更套用程序期間的資料轉換對於目的地提供者而言就是透明的。
假設有另一個案例,其中具有不同資料格式的大量提供者需要互相同步處理資料。其中一種方法是針對每一對提供者撰寫一個轉換器,但是這樣可能會變得無法管理。一個比較好的替代方法是為每個提供者撰寫轉換器,以便在提供者格式和中繼格式間進行轉換。在此情況下會執行兩個資料轉換:從來源提供者轉換到中繼格式,並從中繼格式轉換到目的地提供者格式。
下表顯示 Sync Framework 針對資料轉換所提供的介面和屬性:
Managed 程式碼 | Unmanaged 程式碼 |
---|---|
|
請使用下列方法,轉換每一個提供者的資料:
實作每一個提供者的轉換器。
Managed 程式碼:實作兩個必要的 SyncDataConverter 方法:ConvertDataFromProviderFormat 和 ConvertDataToProviderFormat。
Unmanaged 程式碼:實作兩個必要的 ISyncDataConverter 方法:ConvertDataFromProviderFormat 和 ConvertDataToProviderFormat。
指定同步處理工作階段期間所要使用的轉換器。
Managed 程式碼:將您實作的轉換器指定為兩個 SyncOrchestrator 屬性:LocalDataConverter 和 RemoteDataConverter。
Unmanaged 程式碼:將您實作的轉換器指定在兩個 ISyncDataConversionControl 方法中:SetSourceDataConverter 和 SetDestinationDataConverter。
在大多數狀況下,您只會實作四個可用轉換方法的其中兩個,並針對同步處理工作階段指定這些方法。只有當您使用的資料擷取器不是 IChangeDataRetriever (適用於 Managed 程式碼) 或是 IAsynchronousDataRetriever 或 ISynchronousDataRetriever (適用於 Unmanaged 程式碼) 的實作時,才需要與資料擷取器轉換有關的兩個方法。如果是將資料轉換成中繼狀態的情況,您必須使用 Sync Framework 資料擷取器介面的實作。
Sync Framework 支援有一個或兩個 Unmanaged 提供者之 Managed 應用程式的資料轉換。請注意,轉換程序一定是由 Managed 物件所處理。這可能會導致同步處理的時間要比 Unmanaged 應用程式來得慢。
程式碼範例
下列程式碼範例將示範如何同步處理兩個需要資料轉換的提供者。在 Execute
方法中,程式碼會先具現化即將同步處理的提供者,然後具現化接受輸入和輸出格式的兩個資料轉換類別執行個體。在此範例中,ConvertDataFromProviderFormat
和 ConvertDataToProviderFormat
方法會傳回未變更的資料,不過在實際的應用程式中,您會將輸入格式轉換成適當的輸出格式。
public class SampleConversion
{
public void Execute()
{
SyncOrchestrator orchestrator = new SyncOrchestrator();
orchestrator.Direction = SyncDirectionOrder.Upload;
orchestrator.LocalProvider = new SampleSyncProvider(localStore);
orchestrator.RemoteProvider = new SampleSyncProvider(remoteStore);
DataConverter<DataObject1, DataObject2> localConverter = new DataConverter<DataObject1, DataObject2>();
DataConverter<DataObject2, DataObject3> remoteConverter = new DataConverter<DataObject2, DataObject3>();
orchestrator.LocalDataConverter = localConverter;
orchestrator.RemoteDataConverter = remoteConverter;
orchestrator.Synchronize();
}
string localStore;
string remoteStore;
}
public class DataConverter<SourceType, DestType> : SyncDataConverter
where SourceType : IDataObject, new()
where DestType : IDataObject, new()
{
public DataConverter()
{
}
public override object ConvertDataFromProviderFormat(LoadChangeContext loadChangeContext, object itemData)
{
SourceType dataObj = (SourceType)itemData;
DestType returnData = new DestType();
returnData.Data = dataObj.Data;
return returnData;
}
public override object ConvertDataToProviderFormat(LoadChangeContext loadChangeContext, object itemData)
{
DestType dataObj = (DestType)itemData;
SourceType returnData = new SourceType();
returnData.Data = dataObj.Data;
return returnData;
}
Type sourceType;
Type destType;
}
Public Class SampleConversion
Public Sub Execute()
Dim orchestrator As New SyncOrchestrator()
orchestrator.Direction = SyncDirectionOrder.Upload
orchestrator.LocalProvider = New SampleSyncProvider(localStore)
orchestrator.RemoteProvider = New SampleSyncProvider(remoteStore)
Dim localConverter As New DataConverter(Of DataObject1, DataObject2)()
Dim remoteConverter As New DataConverter(Of DataObject2, DataObject3)()
orchestrator.LocalDataConverter = localConverter
orchestrator.RemoteDataConverter = remoteConverter
orchestrator.Synchronize()
End Sub
Private localStore As String
Private remoteStore As String
End Class
Public Class DataConverter(Of SourceType As {IDataObject, New}, DestType As {IDataObject, New})
Inherits SyncDataConverter
Public Sub New()
End Sub
Public Overloads Overrides Function ConvertDataFromProviderFormat(ByVal loadChangeContext As LoadChangeContext, ByVal itemData As Object) As Object
Dim dataObj As SourceType = DirectCast(itemData, SourceType)
Dim returnData As New DestType()
returnData.Data = dataObj.Data
Return returnData
End Function
Public Overloads Overrides Function ConvertDataToProviderFormat(ByVal loadChangeContext As LoadChangeContext, ByVal itemData As Object) As Object
Dim dataObj As DestType = DirectCast(itemData, DestType)
Dim returnData As New SourceType()
returnData.Data = dataObj.Data
Return returnData
End Function
Private sourceType As Type
Private destType As Type
End Class
下列程式碼範例會定義資料擷取器轉換方法:TryConvertDataRetrieverFromProviderFormat
和 TryConvertDataRetrieverToProviderFormat
。這兩種方法都接受資料擷取器以及變更的清單。為了執行資料擷取器轉換,它們會具現化繼承自 IChangeDataRetriever
的 ConvertedDataRetriever
範例類別。
public override bool TryConvertDataRetrieverFromProviderFormat(
object dataRetrieverIn,
IEnumerable<ItemChange> changes,
out object dataRetrieverOut)
{
dataRetrieverOut = new ConvertedDataRetriever<SourceType, DestType>(dataRetrieverIn);
return true;
}
public override bool TryConvertDataRetrieverToProviderFormat(
object dataRetrieverIn,
IEnumerable<ItemChange> changes,
out object dataRetrieverOut)
{
dataRetrieverOut = new ConvertedDataRetriever<DestType, SourceType>(dataRetrieverIn);
return true;
}
Public Overloads Overrides Function TryConvertDataRetrieverFromProviderFormat(ByVal dataRetrieverIn As Object, ByVal changes As IEnumerable(Of ItemChange), ByRef dataRetrieverOut As Object) As Boolean
dataRetrieverOut = New ConvertedDataRetriever(Of SourceType, DestType)(dataRetrieverIn)
Return True
End Function
Public Overloads Overrides Function TryConvertDataRetrieverToProviderFormat(ByVal dataRetrieverIn As Object, ByVal changes As IEnumerable(Of ItemChange), ByRef dataRetrieverOut As Object) As Boolean
dataRetrieverOut = New ConvertedDataRetriever(Of DestType, SourceType)(dataRetrieverIn)
Return True
End Function
下列程式碼範例會建立 ConvertedDataRetriever
類別並且定義 LoadChangeData
方法和 IdFormats
屬性。轉換資料擷取器時,任何資料轉換所需的程式碼都必須包含在 LoadChangeData
方法中,或由此方法所呼叫。
public class ConvertedDataRetriever<SourceType, DestType> : IChangeDataRetriever
where SourceType : IDataObject, new()
where DestType : IDataObject, new()
{
public ConvertedDataRetriever(object dataRetriever)
{
this.dataRetriever = dataRetriever;
}
public SyncIdFormatGroup IdFormats
{
get
{
return ((IChangeDataRetriever)dataRetriever).IdFormats;
}
}
public object LoadChangeData(LoadChangeContext loadChangeContext)
{
IChangeDataRetriever iRetriever = (IChangeDataRetriever)dataRetriever;
object tempData = iRetriever.LoadChangeData(loadChangeContext);
if (tempData != null)
{
return ConvertData(tempData);
}
return null;
}
private object ConvertData(object itemData)
{
SourceType dataObj = (SourceType)itemData;
DestType returnData = new DestType();
returnData.Data = dataObj.Data;
return returnData;
}
object dataRetriever;
}
Public Class ConvertedDataRetriever(Of SourceType As {IDataObject, New}, DestType As {IDataObject, New})
Implements IChangeDataRetriever
Public Sub New(ByVal dataRetriever As Object)
Me.dataRetriever = dataRetriever
End Sub
Public ReadOnly Property IdFormats() As SyncIdFormatGroup
Get
Return DirectCast(dataRetriever, IChangeDataRetriever).IdFormats
End Get
End Property
Public Function LoadChangeData(ByVal loadChangeContext As LoadChangeContext) As Object
Dim iRetriever As IChangeDataRetriever = DirectCast(dataRetriever, IChangeDataRetriever)
Dim tempData As Object = iRetriever.LoadChangeData(loadChangeContext)
If tempData IsNot Nothing Then
Return ConvertData(tempData)
End If
Return Nothing
End Function
Private Function ConvertData(ByVal itemData As Object) As Object
Dim dataObj As SourceType = DirectCast(itemData, SourceType)
Dim returnData As New DestType()
returnData.Data = dataObj.Data
Return returnData
End Function
Private dataRetriever As Object
End Class