共用方式為


在提供者之間轉換資料

在許多應用程式中,所有提供者都會使用相同的格式同步處理完全相同的資料類型。例如,幾個資料庫同步處理提供者可能會針對 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 程式碼

SyncDataConverter

ISyncDataConverter 介面

LocalDataConverter

ISyncDataConversionControl 介面

RemoteDataConverter

 

請使用下列方法,轉換每一個提供者的資料:

  1. 實作每一個提供者的轉換器。

  2. 指定同步處理工作階段期間所要使用的轉換器。

    • Managed 程式碼:將您實作的轉換器指定為兩個 SyncOrchestrator 屬性:LocalDataConverterRemoteDataConverter

    • Unmanaged 程式碼:將您實作的轉換器指定在兩個 ISyncDataConversionControl 方法中:SetSourceDataConverterSetDestinationDataConverter

在大多數狀況下,您只會實作四個可用轉換方法的其中兩個,並針對同步處理工作階段指定這些方法。只有當您使用的資料擷取器不是 IChangeDataRetriever (適用於 Managed 程式碼) 或是 IAsynchronousDataRetrieverISynchronousDataRetriever (適用於 Unmanaged 程式碼) 的實作時,才需要與資料擷取器轉換有關的兩個方法。如果是將資料轉換成中繼狀態的情況,您必須使用 Sync Framework 資料擷取器介面的實作。

Sync Framework 支援有一個或兩個 Unmanaged 提供者之 Managed 應用程式的資料轉換。請注意,轉換程序一定是由 Managed 物件所處理。這可能會導致同步處理的時間要比 Unmanaged 應用程式來得慢。

程式碼範例

下列程式碼範例將示範如何同步處理兩個需要資料轉換的提供者。在 Execute 方法中,程式碼會先具現化即將同步處理的提供者,然後具現化接受輸入和輸出格式的兩個資料轉換類別執行個體。在此範例中,ConvertDataFromProviderFormatConvertDataToProviderFormat 方法會傳回未變更的資料,不過在實際的應用程式中,您會將輸入格式轉換成適當的輸出格式。

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

下列程式碼範例會定義資料擷取器轉換方法:TryConvertDataRetrieverFromProviderFormatTryConvertDataRetrieverToProviderFormat。這兩種方法都接受資料擷取器以及變更的清單。為了執行資料擷取器轉換,它們會具現化繼承自 IChangeDataRetrieverConvertedDataRetriever 範例類別。

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

請參閱

概念

整合不同提供者的資料