在提供程序间转换数据

在很多应用程序中,所有提供程序只同步格式相同的同类型数据。例如,几个数据库同步提供程序可能为 ADO.NET 数据集中的一组表同步和传输数据。但是,数据格式在某些情况下可能不同。请考虑同步联系人的应用程序。该应用程序使用两个开发人员分别编写的自定义提供程序。这些提供程序所需的数据在以下两个方面存在区别:

  • 提供程序 A 将数据作为字节流传输,而提供程序 B 则将数据作为 XML 流传输。

  • 提供程序 A 的数据包括三个字段:FirstName、LastName 和 PhoneNumber。提供程序 B 的数据包括 FirstName 和 LastName,并将 PhoneNumber 拆分为 PhoneNumber 和 AreaCode。

为了解决此问题,Sync Framework 允许您实现接口,用于将数据转换为每个提供程序所需的格式。针对本文所述的情形,您可以编写一个执行两次转换的转换器:首先将字节流输入转换为 XML 输出,然后将 XML 输入转换为字节流输出。Sync Framework 不要求为两个提供程序都指定转换器。您实现的数据转换代码由同步会话调用,这样数据转换在变更应用过程中对于目标提供程序是透明的。

还考虑这样的情形:大量具有不同数据格式的提供程序需要相互同步数据。一个方法是为每对提供程序编写一个转换器,但是这样做很难管理。一个更好的替代方法是为每个提供程序编写转换器,用于在提供程序数据格式和中间格式之间相互转换。在这种情况下,执行两次数据转换:从源提供程序格式到中间格式以及从中间格式到目标提供程序格式。

下表显示 Sync Framework 为数据转换提供的接口和属性:

托管代码 非托管代码

SyncDataConverter

ISyncDataConverter 接口

LocalDataConverter

ISyncDataConversionControl 接口

RemoteDataConverter

 

使用以下方法为每个提供程序转换数据:

  1. 为每个提供程序实现一个转换器。

  2. 指定在同步会话期间要使用的转换器。

    • 托管代码 - 指定作为两个 SyncOrchestrator 属性 LocalDataConverterRemoteDataConverter 实现的转换器。

    • 非托管代码 - 指定在两个 ISyncDataConversionControl 方法 SetSourceDataConverterSetDestinationDataConverter 中实现的转换器。

在大多数情况下,您将只实现四个可用转换方法中的两个并为同步会话指定它们。只有在您使用的数据检索器不是 IChangeDataRetriever 的实现(对于托管代码)或者不是 IAsynchronousDataRetrieverISynchronousDataRetriever 的实现(对于非托管代码)时,才需要与数据检索器转换有关的两个方法。对于将数据转换为中间状态的情况,必须使用 Sync Framework 数据检索器接口的实现。

Sync Framework 支持其中一个或两个提供程序是非托管的托管应用程序的数据转换。请注意转换过程始终由托管对象处理。如果应用程序是非托管的,同步时间将变长。

代码示例

以下代码示例演示如何同步两个要求进行数据转换的提供程序。在 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。这两个方法都接受数据检索器和变更列表。为了执行数据检索器转换,它们实例化自 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

请参阅

概念

集成来自不同提供程序的数据