プロバイダー間でのデータの変換

多くのアプリケーションでは、すべてのプロバイダーがまったく同じ種類のデータを同じ形式で同期します。たとえば、複数のデータベース同期プロバイダーが、一連のテーブルのデータを 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 に用意されている、データ変換用のインターフェイスとプロパティを示します。

マネージ コード アンマネージ コード

SyncDataConverter

ISyncDataConverter インターフェイス

LocalDataConverter

ISyncDataConversionControl インターフェイス

RemoteDataConverter

 

プロバイダーごとにデータを変換するには、次の方法を使用します。

  1. プロバイダーごとにコンバーターを実装します。

    • マネージ コード 2 つの必須の SyncDataConverter メソッド (ConvertDataFromProviderFormat および ConvertDataToProviderFormat) を実装します。

    • アンマネージ コード 2 つの必須の ISyncDataConverter メソッド (ConvertDataFromProviderFormat および ConvertDataToProviderFormat) を実装します。

  2. 同期セッション中に使用するコンバーターを指定します。

    • マネージ コード 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

参照

概念

異なるプロバイダーのデータの統合