Condividi tramite


Conversione dei dati tra provider

In molte applicazioni tutti i provider sincronizzano esattamente lo stesso tipo di dati nello stesso formato. Ad esempio, diversi provider di sincronizzazione del database potrebbero sincronizzare e trasferire dati per un set di tabelle nei set di dati ADO.NET. Tuttavia, in alcune situazioni, i formati di dati potrebbero essere diversi. Si consideri un'applicazione per la sincronizzazione di contatti. L'applicazione utilizza provider personalizzati scritti da due diversi sviluppatori. I dati richiesti da questi provider differiscono in due aspetti:

  • Il provider A trasferisce i dati come flusso di byte, mentre il provider B trasferisce i dati come flusso XML.

  • I dati dal provider A sono costituiti da tre campi: FirstName, LastName e PhoneNumber. I dati dal provider B includono FirstName e LastName e dividono PhoneNumber in PhoneNumber e AreaCode.

Per gestire questo scenario, Sync Framework consente di implementare interfacce in grado di convertire i dati nel formato richiesto da ogni provider. In questa situazione, scrivere un convertitore che esegua due conversioni: la prima per convertire l'input di un flusso di byte in output XML e la seconda per convertire un input XML nell'output di un flusso di byte. In Sync Framework non è necessario specificare un convertitore per entrambi i provider. Il codice di conversione dei dati implementato viene chiamato dalla sessione di sincronizzazione in modo che la conversione dei dati sia trasparente al provider di destinazione durante il processo di applicazione modifiche.

Si consideri inoltre uno scenario in cui un numero più elevato di provider con formati di dati diversi deve eseguire la sincronizzazione dei dati. Una soluzione consiste nello scrivere un convertitore per ogni coppia di provider, anche se lo scenario potrebbe diventare ingestibile. Una migliore alternativa consiste nello scrivere convertitori per ogni provider in grado di convertire dati in e da un formato intermedio. In questa situazione, vengono eseguite due conversioni di dati: dal provider di origine al formato intermedio e dal formato intermedio al formato del provider di destinazione.

Nella tabella seguente vengono illustrate le interfacce e le proprietà che Sync Framework fornisce per la conversione dei dati:

Codice gestito Codice non gestito

SyncDataConverter

Interfaccia ISyncDataConverter

LocalDataConverter

Interfaccia ISyncDataConversionControl

RemoteDataConverter

 

Utilizzare la soluzione seguente per convertire dati per ogni provider:

  1. Implementare un convertitore per ogni provider.

  2. Specificare i convertitori da utilizzare durante la sessione di sincronizzazione.

    • Codice gestito Specificare i convertitori implementati come le due proprietà SyncOrchestrator: LocalDataConverter e RemoteDataConverter.

    • Codice non gestito Specificare i convertitori implementati nei due metodi ISyncDataConversionControl: SetSourceDataConverter e SetDestinationDataConverter.

Nella maggior parte delle situazioni, verranno implementati solo due dei quattro metodi di conversione disponibili e verranno specificati per la sessione di sincronizzazione. I due metodi correlati alla conversione della funzione di recupero dati sono necessari solo se la funzione di recupero dati utilizzata non è un'implementazione di IChangeDataRetriever (per il codice gestito) o di IAsynchronousDataRetriever o ISynchronousDataRetriever (per il codice non gestito). Per le situazioni in cui si convertono dati in uno stato intermedio, è necessario utilizzare un'implementazione di un'interfaccia della funzione di recupero dati di Sync Framework.

Sync Framework supporta la conversione dei dati per le applicazioni gestite in cui uno o entrambi i provider sono non gestiti. Si tenga presente che il processo di conversione viene sempre gestito da oggetti gestiti. Ne consegue che la sincronizzazione può richiedere una maggiore quantità di tempo quando l'applicazione è gestita.

Esempio di codice

Nell'esempio di codice seguente viene illustrato come sincronizzare due provider che richiedono la conversione dei dati. Nel metodo Execute il primo codice crea le istanze dei provider di cui verrà eseguita la sincronizzazione, quindi crea due istanze della classe di conversione dei dati che accetta un formato di input e output. In questo esempio i metodi ConvertDataFromProviderFormat e ConvertDataToProviderFormat restituiscono dati non modificati, ma in un'applicazione reale sarebbe necessario convertire il formato di input in un formato di output appropriato.

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

Nell'esempio di codice seguente vengono definiti i metodi di conversione della funzione recupero dati TryConvertDataRetrieverFromProviderFormat e TryConvertDataRetrieverToProviderFormat. Entrambi i metodi accettano una funzione recupero dati e un elenco di modifiche. Per eseguire la conversione della funzione recupero dati, viene creata un'istanza della classe di esempio ConvertedDataRetriever che eredita da IChangeDataRetriever.

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

Nell'esempio di codice seguente viene creata la classe ConvertedDataRetriever e vengono definiti il metodo LoadChangeData e la proprietà IdFormats. Durante la conversione delle funzioni recupero dati, il codice richiesto per la conversione dei dati deve essere incluso nel metodo LoadChangeData o chiamato dallo stesso metodo.

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

Vedere anche

Concetti

Integrazione di dati da provider diversi