Conversion de données entre des fournisseurs
Dans de nombreuses applications, tous les fournisseurs synchronisent exactement le même type de données dans le même format. Par exemple, plusieurs fournisseurs de synchronisation de bases de données peuvent synchroniser et transférer des données d'un jeu de tables dans des jeux de données ADO.NET. Cependant, les formats des données peuvent parfois être différents. Prenons l'exemple d'une application qui synchronise des contacts. L'application utilise des fournisseurs personnalisés écrits par deux développeurs. Les données requises par ces fournisseurs diffèrent à deux niveaux :
Le fournisseur A transfère les données sous forme de flux d'octets, alors que le fournisseur B les transfère sous forme de flux XML.
Les données du fournisseur A comprennent les trois champs suivants : FirstName, LastName et PhoneNumber. Les données du fournisseur B incluent les mêmes champs FirstName et LastName, plus deux champs PhoneNumber et AreaCode à la place du champ PhoneNumber du fournisseur A.
Pour répondre aux besoins de ce scénario, Sync Framework vous permet d'implémenter des interfaces qui convertissent les données au format requis par chaque fournisseur. Ainsi, vous devez écrire un convertisseur qui effectue deux conversions : l'une pour convertir une entrée de flux d'octets en sortie XML, l'autre pour convertir une entrée XML en sortie de flux d'octets. Sync Framework ne requiert pas de spécifier un convertisseur pour chaque fournisseur. Le code de conversion des données que vous implémentez est appelé par la session de synchronisation afin que la conversion des données soit transparente pour le fournisseur de destination pendant le processus d'application des modifications.
Prenons l'exemple d'un autre scénario où un plus grand nombre de fournisseurs doivent synchroniser leurs données de formats différents. Une méthode possible consiste à écrire un convertisseur pour chaque paire de fournisseurs, mais cela peut devenir impossible à gérer. Une meilleure méthode est d'écrire des convertisseurs pour chaque fournisseur qui convertissent les données dans un format intermédiaire. Ainsi, deux conversions de données sont effectuées : l'une du fournisseur de source au format intermédiaire et l'autre, du format intermédiaire au format du fournisseur de destination.
Le tableau suivant répertorie les interfaces et propriétés que Sync Framework fournit pour la conversion de données :
Code managé | Code non managé |
---|---|
|
Utilisez la méthode suivante pour convertir les données de chaque fournisseur :
Implémentez un convertisseur pour chaque fournisseur.
Code managé Implémentez les deux méthodes SyncDataConverter obligatoires : ConvertDataFromProviderFormat et ConvertDataToProviderFormat.
Code non managé Implémentez les deux méthodes ISyncDataConverter obligatoires : ConvertDataFromProviderFormat et ConvertDataToProviderFormat.
Spécifiez les convertisseurs à utiliser pendant la session de synchronisation.
Code managé Spécifiez les convertisseurs que vous avez implémentés en utilisant les deux propriétés SyncOrchestrator : LocalDataConverter et RemoteDataConverter.
Code non managé Spécifiez les convertisseurs que vous avez implémentés en utilisant les deux méthodes ISyncDataConversionControl : SetSourceDataConverter et SetDestinationDataConverter.
Dans la plupart des cas, vous implémenterez uniquement deux des quatre méthodes de conversion disponibles et vous les spécifierez pour la session de synchronisation. Les deux méthodes de conversion de l'extracteur de données ne sont obligatoires que si l'extracteur de données que vous utilisez n'est pas une implémentation de IChangeDataRetriever (pour le code managé), ou une implémentation de IAsynchronousDataRetriever ou ISynchronousDataRetriever (pour le code non managé). Si vous convertissez les données dans un format intermédiaire, vous devez utiliser une implémentation d'une interface d'extracteur de données de Sync Framework.
Sync Framework prend en charge la conversion des données pour les applications managées dans lesquelles l'un des fournisseurs ou les deux ne sont pas managés. Gardez à l'esprit que le processus de conversion est toujours géré par les objets managés. Par conséquent, la synchronisation peut être moins rapide que pour une application non managée.
Exemple de code
L'exemple de code suivant démontre la façon de synchroniser deux fournisseurs qui nécessitent des conversions de données. Dans la méthode Execute
, le code instancie d'abord les fournisseurs qui seront synchronisés, puis instancie ensuite deux instances d'une classe de conversion de données qui accepte un format d'entrée et de sortie. Dans cet exemple, les méthodes ConvertDataFromProviderFormat
et ConvertDataToProviderFormat
retournent des données non modifiées, mais dans une application réelle, vous convertiriez le format d'entrée en un format de sortie approprié.
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
L'exemple de code suivant définit les méthodes de conversion de l'extracteur de données TryConvertDataRetrieverFromProviderFormat
et TryConvertDataRetrieverToProviderFormat
. Les deux méthodes acceptent un extracteur de données et une liste de modifications. Afin d'exécuter une conversion de l'extracteur de données, elles instancient un exemple de classe ConvertedDataRetriever
hérité 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
L'exemple de code suivant crée la classe ConvertedDataRetriever
et définit la méthode LoadChangeData
et la propriété IdFormats
. Lors de la conversion des extracteurs de données, tout code requis pour la conversion de données doit être contenu ou appelé par la méthode 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