プロバイダー間でのデータの変換
多くのアプリケーションでは、すべてのプロバイダーがまったく同じ種類のデータを同じ形式で同期します。たとえば、複数のデータベース同期プロバイダーが、一連のテーブルのデータを ADO.NET データセットの形式で同期および転送することがあります。ただし、状況によってはデータ形式が異なる場合もあります。アプリケーションで、連絡先の同期を行うとします。このアプリケーションでは、2 人の開発者が作成したカスタム プロバイダーを使用します。これらのプロバイダーが必要とするデータは、2 つの点で異なります。
プロバイダー A はデータをバイト ストリームとして転送し、プロバイダー B はデータを XML ストリームとして転送する。
プロバイダー A からのデータは、FirstName、LastName、および PhoneNumber という 3 つのフィールドで構成されている。プロバイダー B からのデータには FirstName と LastName が含まれており、PhoneNumber は PhoneNumber と AreaCode に分割されている。
このシナリオに対処するために、Sync Framework では、各プロバイダーが必要とする形式にデータを変換するインターフェイスを実装できます。この場合、2 種類の変換 (バイト ストリーム入力から XML 出力への変換と、XML 入力からバイト ストリーム出力への変換) を実行する 1 つのコンバーターを作成します。Sync Framework では、両方のプロバイダーに対応するコンバーターを指定する必要はありません。実装したデータ変換コードは同期セッションで呼び出されるため、変更適用プロセスの間、データ変換は同期先プロバイダーに対して透過的です。
次に、データ形式の異なる多数のプロバイダーが相互にデータを同期しなければならないシナリオを考えてみましょう。1 つの方法として、プロバイダーのペアごとにコンバーターを作成することもできますが、管理が困難です。そこで、データを中間形式に変換する (および元に戻す) コンバーターをプロバイダーごとに作成することをお勧めします。この場合は 2 種類のデータ変換が行われます。つまり、同期元プロバイダーの形式から中間形式への変換と、中間形式から同期先プロバイダーの形式への変換です。
次の表に、Sync Framework に用意されている、データ変換用のインターフェイスとプロパティを示します。
マネージ コード | アンマネージ コード |
---|---|
|
プロバイダーごとにデータを変換するには、次の方法を使用します。
プロバイダーごとにコンバーターを実装します。
マネージ コード 2 つの必須の SyncDataConverter メソッド (ConvertDataFromProviderFormat および ConvertDataToProviderFormat) を実装します。
アンマネージ コード 2 つの必須の ISyncDataConverter メソッド (ConvertDataFromProviderFormat および ConvertDataToProviderFormat) を実装します。
同期セッション中に使用するコンバーターを指定します。
マネージ コード 2 つの SyncOrchestrator プロパティとして実装したコンバーターを指定します (LocalDataConverter および RemoteDataConverter)。
アンマネージ コード 2 つの ISyncDataConversionControl メソッドで実装したコンバーターを指定します (SetSourceDataConverter および SetDestinationDataConverter)。
通常は、使用できる 4 つの変換メソッドのうちの 2 つだけを実装し、同期セッションに対してそれらを指定します。データ取得元の変換に関係する 2 つのメソッドは、使用するデータ取得元が IChangeDataRetriever の実装 (マネージ コードの場合) ではない場合、あるいは IAsynchronousDataRetriever または ISynchronousDataRetriever の実装 (アンマネージ コードの場合) ではない場合にのみ必要です。データを中間状態に変換する場合は、Sync Framework データ取得元インターフェイスの実装を使用する必要があります。
Sync Framework は、一方または両方のプロバイダーがアンマネージであるマネージ アプリケーションのデータ変換をサポートしています。変換プロセスは常にマネージ オブジェクトによって処理されるということに注意してください。この結果、アプリケーションがアンマネージの場合と比べて同期に時間がかかることがあります。
コード例
次のコード例は、データ変換を必要とする 2 つのプロバイダーを同期する方法を示します。Execute
メソッドで、同期対象のプロバイダーをインスタンス化した後、入出力形式を受け入れるデータ変換クラスの 2 つのインスタンスをインスタンス化します。この例では、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