Convertir datos entre proveedores
Existen muchas aplicaciones donde todos los proveedores sincronizan exactamente el mismo tipo de datos en el mismo formato. Por ejemplo, varios proveedores de sincronización de bases de datos podrían sincronizar y transferir datos para un conjunto de tablas a conjuntos de datos ADO.NET. Sin embargo, los formatos de los datos pueden ser diferentes en algunas situaciones. Considere una aplicación que sincroniza contactos. La aplicación utiliza proveedores personalizados escritos por dos desarrolladores diferentes. Los datos que estos proveedores requieren son diferentes por partida doble:
El proveedor A transfiere datos como una secuencia de bytes, mientras que el proveedor B transfiere datos como una secuencia de XML.
Los datos del proveedor A comprenden tres campos: FirstName, LastName y PhoneNumber. Los datos de proveedor B incluyen FirstName y LastName y dividen PhoneNumber en PhoneNumber y AreaCode.
Para resolver esta situación, Sync Framework le permite implementar interfaces que convierten los datos al formato que requiere cada proveedor. En esta situación, escribiría un convertidor que realiza dos conversiones: la primera convierte entradas en secuencia de bytes a salidas en XML y la segunda convierte entradas en XML a salidas en secuencia de bytes. Sync Framework no requiere que se especifique un convertidor para ambos proveedores. La sesión de sincronización llama al código de sincronización de datos que ha implementado, de forma que la conversión de datos está clara para el proveedor de destino durante el proceso de la aplicación de cambios.
Considere también un escenario donde un gran número de proveedores con formatos de datos diferentes necesitan sincronizar datos entre sí. Un enfoque es escribir un convertidor para cada par de proveedores, pero es posible que en ese caso no se pueda administrar. Una alternativa mejor es escribir convertidores para cada proveedor que convierta datos a y desde un formato intermedio. En esta situación, se efectúan dos conversiones de datos: desde el proveedor de origen al formato intermedio y desde formato intermedio al formato del proveedor de destino.
En la tabla siguiente se muestran las interfaces y propiedades que proporciona Sync Framework para la conversión de datos:
Código administrado | Código no administrado |
---|---|
|
Utilice el siguiente enfoque para convertir los datos de cada proveedor:
Implemente un convertidor para cada proveedor.
Código administrado Implemente los dos métodos requeridos de SyncDataConverter: ConvertDataFromProviderFormat y ConvertDataToProviderFormat.
Código no administrado Implemente los dos métodos requeridos de ISyncDataConverter: ConvertDataFromProviderFormat y ConvertDataToProviderFormat.
Especifique los convertidores que se van a utilizar durante la sesión de sincronización.
Código administrado Especifique los convertidores que haya implementado como las dos propiedadesSyncOrchestrator: LocalDataConverter y RemoteDataConverter.
Código no administrado Especifique los convertidores que haya implementado en los dos métodos ISyncDataConversionControl: SetSourceDataConverter y SetDestinationDataConverter.
En la mayoría de las situaciones, implementará solamente dos de los cuatro métodos de conversión disponibles y los especificará para la sesión de sincronización. Los dos métodos asociados a la conversión del recuperador de datos serán necesarios únicamente si el recuperador de datos que utiliza no es una implementación de IChangeDataRetriever (para código administrado), o bien IAsynchronousDataRetriever o ISynchronousDataRetriever (para código no administrado). Para las situaciones en las que convierte datos a un estado intermedio, debe utilizar una implementación de una interfaz del recuperador de datos de Sync Framework.
Sync Framework admite la conversión de datos para las aplicaciones administradas en las que uno o dos de los proveedores no están administrados. Tenga en cuenta que los objetos administrados son los que se ocupan siempre del proceso de conversión. Esto puede producir tiempos de sincronización más lentos en comparación con una aplicación no administrada.
Ejemplo de código
En el ejemplo de código siguiente se muestra la forma de sincronizar dos proveedores que requieren conversión de datos. En el método Execute
, el código crea primeramente instancias de los proveedores que se sincronizarán y, a continuación, crea instancias de dos instancias de la clase de conversión de datos que acepta un formato de entrada y de salida. En este ejemplo, los métodos ConvertDataFromProviderFormat
y ConvertDataToProviderFormat
devuelven datos no modificados pero, en una aplicación real, convertiría el formato de entrada en un formato de salida apropiado.
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
En el ejemplo de código siguiente se definen los métodos de conversión del recuperador de datos TryConvertDataRetrieverFromProviderFormat
y TryConvertDataRetrieverToProviderFormat
. Ambos métodos aceptan un recuperador de datos y una lista de cambios. Para realizar la conversión del recuperador de datos, crean una instancia de una clase de ejemplo ConvertedDataRetriever
que hereda de 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
En el ejemplo de código siguiente se crea la clase ConvertedDataRetriever
y se definen el método LoadChangeData
y la propiedad IdFormats
. En la conversión de recuperadores de datos, el código necesario para la conversión de datos debe estar contenido en el método LoadChangeData
o debe ser invocado por este método.
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