Convertendo dados entre provedores
Em muitos aplicativos, todos os provedores sincronizam exatamente o mesmo tipo de dados no mesmo formato. Por exemplo, vários provedores de sincronização de banco de dados poderiam sincronizar e transferir dados para um conjunto de tabelas em conjuntos de dados do ADO.NET. Porém, em algumas situações, os formatos de dados podem ser diferentes. Considere um aplicativo que sincroniza contatos. O aplicativo usa provedores personalizados escritos por dois desenvolvedores diferentes. Os dados que esses provedores exigem são diferentes de duas maneiras:
O provedor A transfere dados como um fluxo de bytes, enquanto o provedor B transfere dados como um fluxo XML.
Os dados do provedor A consistem em três campos: FirstName, LastName e PhoneNumber. Os dados do provedor B incluem FirstName e LastName, e dividem PhoneNumber em PhoneNumber e AreaCode.
Para abordar esse cenário, o Sync Framework permite implementar interfaces que convertem dados no formato exigido por cada provedor. Nessa situação, você escreveria um conversor que executa duas conversões: a primeira converte uma entrada de fluxo de bytes em uma saída XML, e a segunda converte uma entrada XML em uma saída de fluxo de bytes. O Sync Framework não exige que seja especificado um conversor para os dois provedores. O código de conversão de dados implementado é chamado pela sessão de sincronização de forma que a conversão de dados é transparente ao provedor de destino durante o processo de aplicação de alterações.
Considere também um cenário no qual um número maior de provedores com formatos de dados diferentes precisa sincronizar seus dados. Uma abordagem é escrever um conversor para cada par de provedores, mas isso pode ser impossível de gerenciar. Uma alternativa melhor é escrever conversores para cada provedor que convertem dados de e para um formato intermediário. Nessa situação, são executadas duas conversões de dados: do provedor de origem para o formato intermediário e do formato intermediário para o formato do provedor de destino.
A tabela a seguir mostra as interfaces e as propriedades fornecidas pelo Sync Framework para a conversão de dados:
Código gerenciado | Código não gerenciado |
---|---|
|
Use a seguinte abordagem para converter dados para cada provedor:
Implemente um conversor para cada provedor.
Código gerenciado Implemente os dois métodos SyncDataConverter necessários: ConvertDataFromProviderFormat e ConvertDataToProviderFormat.
Código não gerenciado Implemente os dois métodos ISyncDataConverter necessários: ConvertDataFromProviderFormat e ConvertDataToProviderFormat.
Especifique os conversores que devem ser usados durante a sessão de sincronização.
Código gerenciado Especifique os conversores que você implementou como as duas propriedades SyncOrchestrator: LocalDataConverter e RemoteDataConverter.
Código não gerenciado Especifique os conversores que você implementou nos dois métodos ISyncDataConversionControl: SetSourceDataConverter e SetDestinationDataConverter.
Na maioria das situações, você implementará apenas dois dos quatro métodos de conversão disponíveis e os especificará para a sessão de sincronização. Os dois métodos relacionados à conversão do recuperador de dados serão necessários somente se o recuperador de dados usado não for uma implementação de IChangeDataRetriever (para código gerenciado), IAsynchronousDataRetriever ou ISynchronousDataRetriever (para código não gerenciado). Para situações nas quais você converte dados para um estado intermediário, use uma implementação de uma interface de recuperador de dados do Sync Framework.
O Sync Framework dá suporte à conversão de dados para aplicativos gerenciados nos quais um ou os dois provedores são não gerenciados. Lembre-se de que o processo de conversão sempre é tratado por objetos gerenciados. Isso pode resultar em um tempo de sincronização maior que se o aplicativo for não gerenciado.
Exemplo de código
O exemplo de código a seguir demonstra como sincronizar dois provedores que exigem conversão de dados. No método Execute
, o código primeiro instancia os provedores que serão sincronizados e, em seguida, cria duas instâncias da classe de conversão de dados que aceita um formato de entrada e de saída. Neste exemplo, os métodos ConvertDataFromProviderFormat
e ConvertDataToProviderFormat
retornam dados inalterados, mas em um aplicativo real você converteria o formato de entrada em um formato de saída apropriado.
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
O exemplo de código a seguir define os métodos de conversão do recuperador de dados TryConvertDataRetrieverFromProviderFormat
e TryConvertDataRetrieverToProviderFormat
. Os dois métodos aceitam um recuperador de dados e uma lista de alterações. Para executar a conversão do recuperador de dados, eles instanciam uma classe de exemplo ConvertedDataRetriever
que herda 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
O exemplo de código a seguir cria a classe ConvertedDataRetriever
e define o método LoadChangeData
e a propriedade IdFormats
. Ao converter recuperadores de dados, qualquer código necessário para conversão de dados deve estar contido no método LoadChangeData
ou ser chamado por ele.
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