Premiers pas avec Microsoft Synchronization Framework For ADO .NET - Version 1.0
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
Premiers pas avec Microsoft Synchronization Framework For ADO .NET Version 1.0 James RAVAILLE http://blogs.dotnet-france.com/jamesr
2 Premiers pas avec Microsoft Synchronization Framework For ADO .NET Sommaire 1 Introduction ..................................................................................................................................... 3 1.1 Présentation ............................................................................................................................ 3 1.2 Pré-requis ................................................................................................................................ 3 2 Présentation de l’application .......................................................................................................... 4 2.1 Architecture de l’application ................................................................................................... 4 2.2 Construction de la base de données ....................................................................................... 4 2.2.1 Schéma de base de données ........................................................................................... 4 2.2.2 Script de création ............................................................................................................ 4 3 Création de l’application ................................................................................................................. 7 3.1 Création du projet ................................................................................................................... 7 3.2 Création du composant de synchronisation ........................................................................... 7 3.3 Création de l’interface graphique ......................................................................................... 12 3.3.1 Présentation de l’interface ............................................................................................ 12 3.3.2 Mouvement et gestion des données ............................................................................. 14 3.3.3 Implémentation des actions .......................................................................................... 15 3.4 Exécution et test de l’application .......................................................................................... 21 3.5 Mise en œuvre de la synchronisation bi-directionnelle ........................................................ 22 4 Gestion des conflits de données ................................................................................................... 24 4.1 Présentation des cas de conflit de données .......................................................................... 24 4.2 Présentation du formulaire de gestion de conflits de données ............................................ 24 4.3 Réalisation du formulaire de gestion de conflits de données ............................................... 24 4.4 Résolution des conflits de données....................................................................................... 26 5 Conclusion .............................................. Erreur ! Signet non défini.Error! Bookmark not defined. Dotnet France Association – James RAVAILLE
3 Premiers pas avec Microsoft Synchronization Framework For ADO .NET 1 Introduction 1.1 Présentation Dans ce cours, nous allons mettre en œuvre les composants de Synchronization Framework For ADO .NET, sous-ensemble de Microsoft Synchronization Framework. Nous allons créer une application, permettant de synchroniser des données entre une base de données locale de type SQL Server CE, et une base de données distante de type SQL Server 2008. 1.2 Pré-requis Nous vous conseillons de lire les cours suivants, publiés sur Dotnet-France: - Les bases fondamentales d’ADO .NET. - L’introduction à Microsoft Synchronization Framework. - Les bases fondamentales de Synchronization Framework For ADO .NET. Dotnet France Association – James RAVAILLE
4 Premiers pas avec Microsoft Synchronization Framework For ADO .NET 2 Présentation de l’application 2.1 Architecture de l’application Voici l’architecture de l’application que nous allons développer : TCP/IP Serveur de bases de données SQL Server 2008 Cette application affiche et gère des données en mode CRUD. Ces données sont contenues dans une base de données SQL Server 2008 distante. Pour mettre en œuvre Synchronization Framework For ADO .NET, cette application possède une source de données locale, implémentée par une base de données SQL Server CE (fichier d’extension .sdf). 2.2 Construction de la base de données 2.2.1 Schéma de base de données Nous allons créer la base de données SQL Server 2008, nommée DotnetFrance, dont le diagramme est le suivant : 2.2.2 Script de création Voici un script permettant de créer la base de données : Dotnet France Association – James RAVAILLE
5 Premiers pas avec Microsoft Synchronization Framework For ADO .NET -- SQL CREATE TABLE [dbo].[Stagiaire]( [Identifiant] [int] IDENTITY(1,1) NOT NULL, [Nom] [varchar](50) NOT NULL, [Prenom] [varchar](50) NOT NULL, CONSTRAINT [PK_Stagiaire] PRIMARY KEY CLUSTERED ( [Identifiant] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], CONSTRAINT [UQ__Stagiaire__7F60ED59] UNIQUE NONCLUSTERED ( [Identifiant] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO CREATE TABLE [dbo].[Cours]( [Identifiant] [int] IDENTITY(1,1) NOT NULL, [Libelle] [varchar](50) NOT NULL, [NombreJours] [int] NOT NULL, CONSTRAINT [PK_Cours] PRIMARY KEY CLUSTERED ( [Identifiant] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY], CONSTRAINT [UQ__Cours__023D5A04] UNIQUE NONCLUSTERED ( [Identifiant] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO CREATE TABLE [dbo].[Stagiaire2Cours]( [IdStagiaire] [int] NOT NULL, [IdCours] [int] NOT NULL, CONSTRAINT [PK_Stagiaire2Cours] PRIMARY KEY CLUSTERED ( [IdStagiaire] ASC, [IdCours] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO ALTER TABLE [dbo].[Stagiaire2Cours] WITH CHECK ADD CONSTRAINT [FK_Stagiaire2Cours_Cours] FOREIGN KEY([IdCours]) REFERENCES [dbo].[Cours] ([Identifiant]) ON UPDATE CASCADE ON DELETE CASCADE GO ALTER TABLE [dbo].[Stagiaire2Cours] WITH CHECK ADD CONSTRAINT [FK_Stagiaire2Cours_Stagiaire] FOREIGN KEY([IdStagiaire]) REFERENCES [dbo].[Stagiaire] ([Identifiant]) ON UPDATE CASCADE ON DELETE CASCADE GO ALTER TABLE [dbo].[Stagiaire2Cours] CHECK CONSTRAINT [FK_Stagiaire2Cours_Stagiaire] GO Dotnet France Association – James RAVAILLE
6 Premiers pas avec Microsoft Synchronization Framework For ADO .NET Et voici un script permettant de l’alimenter en données : -- SQL USE [DotnetFrance] GO /****** Object: Table [dbo].[Stagiaire] ******/ SET IDENTITY_INSERT [dbo].[Stagiaire] ON INSERT [dbo].[Stagiaire] ([Identifiant], [Nom], [Prenom]) VALUES (1, N'DEROUX', N'Alain') INSERT [dbo].[Stagiaire] ([Identifiant], [Nom], [Prenom]) VALUES (2, N'RAVAILLE', N'James') INSERT [dbo].[Stagiaire] ([Identifiant], [Nom], [Prenom]) VALUES (3, N'SIRON', N'Karl') INSERT [dbo].[Stagiaire] ([Identifiant], [Nom], [Prenom]) VALUES (4, N'EMATO', N'Julie') SET IDENTITY_INSERT [dbo].[Stagiaire] OFF /****** Object: Table [dbo].[Cours] ******/ SET IDENTITY_INSERT [dbo].[Cours] ON INSERT [dbo].[Cours] ([Identifiant], [Libelle], [NombreJours]) VALUES (1, N'SQL Server - Administration de serveurs', 5) INSERT [dbo].[Cours] ([Identifiant], [Libelle], [NombreJours]) VALUES (2, N'XHTML / CSS', 3) INSERT [dbo].[Cours] ([Identifiant], [Libelle], [NombreJours]) VALUES (3, N'C#', 5) INSERT [dbo].[Cours] ([Identifiant], [Libelle], [NombreJours]) VALUES (4, N'ASP .NET 3.5', 5) INSERT [dbo].[Cours] ([Identifiant], [Libelle], [NombreJours]) VALUES (5, N'ASP .NET AJAX', 3) SET IDENTITY_INSERT [dbo].[Cours] OFF /****** Object: Table [dbo].[Stagiaire2Cours] ******/ INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (1, 1) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (1, 3) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (2, 1) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (2, 2) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (2, 3) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (2, 4) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (3, 1) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (3, 4) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (3, 5) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (4, 4) INSERT [dbo].[Stagiaire2Cours] ([IdStagiaire], [IdCours]) VALUES (4, 5) Dotnet France Association – James RAVAILLE
7 Premiers pas avec Microsoft Synchronization Framework For ADO .NET 3 Création de l’application 3.1 Création du projet Après avoir ouvert Visual Studio, créons un projet de type Windows Forms, nommé AppliSynchroDonnees : 3.2 Création du composant de synchronisation Pour créer un composant de synchronisation de données, ajoutons à la racine de notre projet, un composant de type « Cache de base de données locale », nommé CompoSynchro : Dotnet France Association – James RAVAILLE
8 Premiers pas avec Microsoft Synchronization Framework For ADO .NET Après avoir cliqué sur le bouton Ajouter, la fenêtre suivante apparaît : 2 1 3 4 6 5 Commençons par sélectionner une connexion vers votre base de données SQL Server (1), ou en créer une si elle n’existe pas (2). Dans le cas où votre connexion utilise l’authentification SQL Server pour se connecter sur le serveur de base de données, la fenêtre suivante apparaît : Dotnet France Association – James RAVAILLE
9 Premiers pas avec Microsoft Synchronization Framework For ADO .NET Saisissons le mot de passe de l’utilisateur, puis validons. Revenu sur la fenêtre précédente : - Nous ne modifions pas la connexion Cliente. Lors de la validation, cet assistant créera un fichier de base de données local (d’extension .sdf). (3) - Nous décidons d’utiliser le mécanisme de suivi des modifications proposées par SQL Server 2008 (4). Ainsi, il ne sera pas nécessaire de modifier la structure des tables, pour lesquelles nous souhaitons assurer le suivi. - Nous synchronisons les données au sein d’une transaction (6). - Cliquons sur le bouton Ajouter (en bas à droite - 5). La fenêtre suivante apparaît : Dotnet France Association – James RAVAILLE
10 Premiers pas avec Microsoft Synchronization Framework For ADO .NET Sélectionnons les tables pour lesquelles nous voulons synchroniser les données. Dans notre application, nous le gérons uniquement pour la table Stagiaire. Etant donné que nous avons précédemment choisi, le système de suivi des modifications proposé par SQL server 2008, les options de détections et d’application des modifications sont désactivées pour les tables à synchroniser (tables sélectionnées). En cliquant sur le bouton OK, la fenêtre suivante apparaît : Une fois cette étape réalisée, la fenêtre suivante apparaît : Choisissons les champs des tables que nous souhaitons synchroniser. Dans notre cas, nous sélectionnons tous les champs de la table. Puis cliquons sur le bouton « Terminer ». De nombreuses opérations sont effectuées par Visual Studio sur notre projet : - Ajout des références : Dotnet France Association – James RAVAILLE
11 Premiers pas avec Microsoft Synchronization Framework For ADO .NET o Microsoft.Synchronization.Data o Microsoft.Synchronization.Data.Server o Microsoft.Synchronization.Data.SqlServerCe o System.Data.SqlServerCe o System.Transactions - Le fichier CompoSynchro.sync est créé. Ce fichier contient tous les paramètres que nous venons de définir. - Un répertoire nommé SQLScripts contenant les fichiers suivant : o CompoSynchro.DotnetFrance.sql : script SQL permettant d’activer la surveillance des modifications des données sur la base de données DotnetFrance. -- SQL IF NOT EXISTS (SELECT * FROM sys.change_tracking_databases WHERE database_id = DB_ID(N'DotnetFrance')) ALTER DATABASE [DotnetFrance] SET CHANGE_TRACKING = ON GO o CompoSynchro.dbo.Stagiaire.sql : script SQL permettant d’activer la surveillance des modifications des données sur la table Stagiaire. Un fichier de ce type est généré par table synchronisée. -- SQL IF NOT EXISTS (SELECT * FROM sys.change_tracking_tables WHERE object_id = OBJECT_ID(N'[dbo].[Stagiaire]')) ALTER TABLE [dbo].[Stagiaire] ENABLE CHANGE_TRACKING GO - Un autre répertoire nommé SQLUndoScripts contenant les fichiers CompoSynchro.DotnetFrance.disable.sql et CompoSynchro.dbo.Stagiaire.disable.sql. A l’inverse des scripts précédents, ils permettent respectivement d’annuler la surveillance des données sur la base de données DotnetFrance et la table Stagiaire : -- SQL IF EXISTS (SELECT * FROM sys.change_tracking_databases WHERE database_id = DB_ID(N'DotnetFrance')) ALTER DATABASE [DotnetFrance] SET CHANGE_TRACKING = OFF GO -- SQL IF EXISTS (SELECT * FROM sys.change_tracking_tables WHERE object_id = OBJECT_ID(N'[dbo].[Stagiaire]')) ALTER TABLE [dbo].[Stagiaire] DISABLE CHANGE_TRACKING GO Dotnet France Association – James RAVAILLE
12 Premiers pas avec Microsoft Synchronization Framework For ADO .NET - Création du fichier DotnetFrance.sdf. Il constitue une source de données locale pour notre application, sous forme de fichier. La propriété « Copier dans le répertoire de sortie », à savoir le répertoire d’exécution de l’application, est valorisée à « Copier si plus récent ». Ce fichier sera à déployer lors du déploiement de l’application. Il constitue une base de données qui contient autant de tables qu’il y a de tables à synchroniser. Dans notre cas, elle ne contiendra qu’une seule table, nommée Stagiaire. Elle aura les mêmes champs et contraintes que la table Stagiaire de la base de données distante. - Le fichier DotnetFranceDataSet.xsd est créé. Il s’agit d’un DataSet typé permettant d’accéder aux données contenues dans le fichier DotnetFrance.sdf. - Le fichier de configuration est modifié, de manière à contenir deux chaînes de connexion : o Une vers la base de données distante (DotnetFrance). o Une vers la base de données locale (DotnetFrance.sdf). Une fois cette étape terminée, notre base de données a été configurée, et la nous avons créé notre source de données locale, enfin créer et configurer de manière « basique » notre composant de synchronisation. En effet, toutes les tâches liées à la synchronisation de données ne sont pas traitées. Par exemple, les conflits de synchronisation (des mêmes données modifiées à la fois côté client et côté serveur) ne sont pas traités. Cependant, Synchronization Framework For ADO .NET met à notre disposition des mécanismes de gestion de conflits, que nous étudierons ultérieurement dans ce cours. 3.3 Création de l’interface graphique 3.3.1 Présentation de l’interface Voici l’interface graphique du formulaire principal de notre application, que nous allons construire : Dotnet France Association – James RAVAILLE
13 Premiers pas avec Microsoft Synchronization Framework For ADO .NET 6 1 2 5 4 3 Elle doit permettre : - De synchroniser la base de données distante, et la source de données locale DotnetFrance.sdf de l’application, via le bouton Synchroniser (1). - D’afficher les données contenues dans la base de données locales (2). Pour ce faire, nous utiliserons le DataSet typé DotnetFranceDataSet.xsd. - De permettre à l’utilisateur d’ajouter, de modifier et de supprimer un stagiaire (au travers de la grille - 3). - De valider (avec le bouton Up - 4) ou d’annuler les modifications (avec le bouton Down - 2). Ce formulaire affiche aussi des informations : - Concernant la gestion des données dans la base de données locale : nombre d’enregistrements à ajouter / modifier / supprimer (5). Ces données sont réinitialisées à 0 lors de la validation ou annulation des données dans la source de données locale. - Concernant la synchronisation entre la base de données locale et la base de données distantes (6): Dotnet France Association – James RAVAILLE
14 Premiers pas avec Microsoft Synchronization Framework For ADO .NET o Heure de départ de la synchronisation ; o Heure de fin de la synchronisation ; o Nombre d’enregistrements total à uploader ; uploadés et ayant levé une erreur (par exemple, pour un conflit de données) ; o Nombre d’enregistrements total à downloader ; downloadés et ayant levé une erreur. 3.3.2 Mouvement et gestion des données Voici un schéma présentant les mouvements de données entre les différents endroits de stockage de l’application : Composant de synchronisation TableAdapter Sync Framework Synchronisation Alimentation / répercution bidirectionnelle des modifications Annulation des modifications (opération mémoire) Base de données distante Base de données locale DataSet typé SQL Server 2008 Comme le montre le schéma ci-dessus, il existe trois endroits de stockage pour l’application, qu’il est nécessaire de bien distinguer : - La base de données SQL Server, base de données distante, utilisée par tous les utilisateurs de l’application. - La base de donnes locale DotnetFrance.sdf, propre à l’application. - Le DataSet, qui permet de gérer les données contenues dans la base de données locale, en utilisant les objets du modèle ADO .NET en mode déconnecté (en l’occurrence un DataSet typé, contenant des DataTable et des TableAdapters). Les composants de l’application, permettant de manipuler les données contenues dans ces sources de données, sont multiples : - Le composant de synchronisation Sync Framework. Dans notre exemple, nous choisissons la synchronisation bidirectionnelle. Autrement dit, toutes les modifications effectuées dans la base de données locales seront répercutées dans la base de données distante, et vice-versa. - Les TableAdapters : composants DataAdapters spécialisés, définis dans le DataSet typé, pour gérer en mode CRUD les données contenues dans une table particulère. Ils permettent de lire des données dans la base de données locales pour alimenter une table du DataSet typé, et de répercuter dans cette même table de cette même base, toutes les modifications effectuées par l’utilisateur dans cette table. Dans notre cas, Dotnet France Association – James RAVAILLE
15 Premiers pas avec Microsoft Synchronization Framework For ADO .NET notre DataSet ne contenant qu’une seule table (stagiaire), un seul TableAdapter a été créé. - Un contrôle de type BindingSource nommé BdsStagiaires, permet d’alimenter la grille des stagiares. 3.3.3 Implémentation des actions 3.3.3.1 Les objets gérés par le formulaire Dans les différentes méthodes du formulaire que nous allons présenter ci-dessous, nous allons gérer les objets suivants : - Une instance du DataSet typé DotnetFranceDataSet, nommée oDataSet. - Une instance de la classe StagiaireTableAdapter, permettant d’alimenter le DataSet typé DotnetFranceDataSet et de répercuter les modifications effectuées sur la source de données DotnetFrance.sdf. - Une instance du composant de synchronisation CompoSynchroClientSyncProvider, nommée AgentSynchro. Ainsi, soit les déclarations suivantes, constituant les attributs du formulaire : // C# DotnetFranceDataSet oDataSet; StagiaireTableAdapter oStagiaireTableAdapter; CompoSynchroSyncAgent oAgentSynchro; ' VB.NET Dim oDataSet As DotnetFranceDataSet Dim oStagiaireTableAdapter As StagiaireTableAdapter Dim oAgentSynchro As CompoSynchroSyncAgent Remarque : pour utiliser la classe oStagiaireTableAdapter, importer l’espace de nom AppliSynchroDonnees.DotnetFranceDataSetTableAdapters. 3.3.3.2 Chargement du formulaire Lors du chargement du formulaire en mémoire, nous allons instancier les attributs déclarés ci-dessus. Ainsi, en implémentant l’évènement Load sur notre formulaire, nous écrivons le bloc d’instructions suivant : // C# private void FrmSynchroDonnees_Load(object sender, EventArgs e) { oDataSet = new DotnetFranceDataSet(); oStagiaireTableAdapter = new StagiaireTableAdapter(); oAgentSynchro = new CompoSynchroSyncAgent(); } Dotnet France Association – James RAVAILLE
16 Premiers pas avec Microsoft Synchronization Framework For ADO .NET ' VB.NET Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load oDataSet = New DotnetFranceDataSet() oStagiaireTableAdapter = New StagiaireTableAdapter() oAgentSynchro = New CompoSynchroSyncAgent() End Sub Ainsi, nous pouvons utiliser ces objets dans toutes les autres méthodes de notre formulaire. 3.3.3.3 Synchronisation des données entre la base de données distante et la base de données locale Nous implémentons l’évènement Click sur le bouton dont le libellé est Synchroniser // C# private void CmdSynchroniser_Click(object sender, EventArgs e) { // Gestion des conflits. CompoSynchroClientSyncProvider clientSyncProvider = (CompoSynchroClientSyncProvider)oAgentSynchro.LocalProvider; //syncAgent.Stagiaire.SyncDirection = SyncDirection.Bidirectional; SyncStatistics syncStats = oAgentSynchro.Synchronize(); // Affichage des stastistiques sur la synchronisation. this.AfficherInfosSynchronisation(syncStats); // Chargement des données. oStagiaireTableAdapter.Fill(oDataSet.Stagiaire); BdsStagiaires.DataSource = oDataSet.Stagiaire; } ' VB.NET Private Sub CmdSynchroniser_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdSynchroniser.Click ' Gestion des conflits. Dim clientSyncProvider As CompoSynchroClientSyncProvider = CType(oAgentSynchro.LocalProvider, CompoSynchroClientSyncProvider) 'syncAgent.Stagiaire.SyncDirection = SyncDirection.Bidirectional; Dim syncStats As SyncStatistics = oAgentSynchro.Synchronize() ' Affichage des stastistiques sur la synchronisation. Me.AfficherInfosSynchronisation(syncStats) ' Chargement des données. oStagiaireTableAdapter.Fill(oDataSet.Stagiaire) BdsStagiaires.DataSource = oDataSet.Stagiaire End Sub Dotnet France Association – James RAVAILLE
17 Premiers pas avec Microsoft Synchronization Framework For ADO .NET Remarque : pour utiliser la classe SyncStatistics, importer l’espace de nom Microsoft.Synchronization.Data. 3.3.3.4 Affichage des informations sur la synchronisation Dans le bloc de code présenté ci-dessus, une méthode nommée AfficherInfosSynchronisation est utilisée pour afficher les informations résultant de la dernière synchronisation. Voici son implémentation : // C# private void AfficherInfosSynchronisation(SyncStatistics aStatsSynchro) { TxtHeureDebutSynchronisation.Text = aStatsSynchro.SyncStartTime.ToString(); TxtHeureFinSynchronisation.Text = aStatsSynchro.SyncCompleteTime.ToString(); TxtNombreModificationsDownloadees.Text = aStatsSynchro.TotalChangesDownloaded.ToString(); TxtNombreModificationsDownloadeesAppliquees.Text = aStatsSynchro.DownloadChangesApplied.ToString(); TxtNombreModificationsDownloadeesEnErreur.Text = aStatsSynchro.DownloadChangesFailed.ToString(); TxtNombreModificationsUploadees.Text = aStatsSynchro.TotalChangesUploaded.ToString(); TxtNombreModificationsUploadeesAppliquees.Text = aStatsSynchro.UploadChangesApplied.ToString(); TxtNombreModificationsUploadeesEnErreur.Text = aStatsSynchro.UploadChangesFailed.ToString(); } ' VB.NET Private Sub AfficherInfosSynchronisation(ByVal aStatsSynchro As SyncStatistics) TxtHeureDebutSynchronisation.Text = aStatsSynchro.SyncStartTime.ToString() TxtHeureFinSynchronisation.Text = aStatsSynchro.SyncCompleteTime.ToString() TxtNombreModificationsDownloadees.Text = aStatsSynchro.TotalChangesDownloaded.ToString() TxtNombreModificationsDownloadeesAppliquees.Text = aStatsSynchro.DownloadChangesApplied.ToString() TxtNombreModificationsDownloadeesEnErreur.Text = aStatsSynchro.DownloadChangesFailed.ToString() TxtNombreModificationsUploadees.Text = aStatsSynchro.TotalChangesUploaded.ToString() TxtNombreModificationsUploadeesAppliquees.Text = aStatsSynchro.UploadChangesApplied.ToString() TxtNombreModificationsUploadeesEnErreur.Text = aStatsSynchro.UploadChangesFailed.ToString() End Sub Dotnet France Association – James RAVAILLE
18 Premiers pas avec Microsoft Synchronization Framework For ADO .NET 3.3.3.5 Affichage des modifications en cours sur le DataSet typé Dans le bloc de code présenté ci-dessus, une méthode est utilisée pour afficher les modifications en cours dans le DataSet typé local (nombre de stagiaires marqués pour l’ajout, pour la modification et pour la suppression). Cette méthode est appelée lors de tout changement de ligne dans la liste des stagiaires affichée : // C# private void AfficherInformationsDataSetType() { TxtNombreAjouts.Text = "0"; TxtNombreModifs.Text = "0"; TxtNombreAjouts.Text = "0"; if (oDataSet.Stagiaire != null && oDataSet.Stagiaire.GetChanges() != null) { if (oDataSet.Stagiaire.GetChanges(DataRowState.Added) != null) { TxtNombreAjouts.Text = oDataSet.Stagiaire.GetChanges(DataRowState.Added).Rows.Count.ToString(); } if (oDataSet.Stagiaire.GetChanges(DataRowState.Modified) != null) { TxtNombreModifs.Text = oDataSet.Stagiaire.GetChanges(DataRowState.Modified).Rows.Count.ToString( ); } if (oDataSet.Stagiaire.GetChanges(DataRowState.Deleted) != null) { TxtNombreSuppression.Text = oDataSet.Stagiaire.GetChanges(DataRowState.Deleted).Rows.Count.ToString() ; } } } private void BdsStagiaires_CurrentChanged(object sender, EventArgs e) { this.AfficherInformationsDataSetType(); } Dotnet France Association – James RAVAILLE
19 Premiers pas avec Microsoft Synchronization Framework For ADO .NET ' VB.NET Private Sub AfficherInformationsDataSetType() TxtNombreAjouts.Text = "0" TxtNombreModifs.Text = "0" TxtNombreAjouts.Text = "0" If (oDataSet.Stagiaire IsNot Nothing AndAlso oDataSet.Stagiaire.GetChanges() IsNot Nothing) Then If (oDataSet.Stagiaire.GetChanges(DataRowState.Added) IsNot Nothing) Then TxtNombreAjouts.Text = oDataSet.Stagiaire.GetChanges(DataRowState.Added).Rows.Count.ToString() End If If (oDataSet.Stagiaire.GetChanges(DataRowState.Modified) IsNot Nothing) Then TxtNombreModifs.Text = oDataSet.Stagiaire.GetChanges(DataRowState.Modified).Rows.Count.ToString( ) End If If (oDataSet.Stagiaire.GetChanges(DataRowState.Deleted) IsNot Nothing) Then TxtNombreSuppression.Text = oDataSet.Stagiaire.GetChanges(DataRowState.Deleted).Rows.Count.ToString() End If End If End Sub Private Sub BdsStagiaires_CurrentChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BdsStagiaires.CurrentChanged Me.AfficherInformationsDataSetType() End Sub 3.3.3.6 Répercution des modifications effectuées sur le DataSet typé vers la base de données locale Le bloc de code ci-dessous permet de mettre à jour la source de données locale de l’application (DotnetFrance.sdf), avec les données contenues dans le DataSet typé. Il correspond à l’implémentation de l’évènement Click sur le bouton CmdValiderModifications labellisé UP : // C# private void CmdValiderModifications_Click(object sender, EventArgs e) { oStagiaireTableAdapter.Update(oDataSet.Stagiaire); this.AfficherInformationsBaseDonneesLocale(); } Dotnet France Association – James RAVAILLE
20 Premiers pas avec Microsoft Synchronization Framework For ADO .NET ' VB.NET Private Sub CmdValiderModifications_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdValiderModifications.Click oStagiaireTableAdapter.Update(oDataSet.Stagiaire) Me.AfficherInformationsBaseDonneesLocale() End Sub 3.3.3.7 Annulation des modifications effectuées sur le DataSet typé Le bloc de code ci-dessous permet d’annuler les données contenues dans le DataSet typé. Il correspond à l’implémentation de l’évènement Click sur le bouton CmdAnnulerModification labellisé DOWN : // C# private void CmdAnnulerModification_Click(object sender, EventArgs e) { oDataSet.Stagiaire.RejectChanges(); this.AfficherInformationsDataSetType(); } ' VB.NET Private Sub CmdAnnulerModification_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdAnnulerModification.Click oDataSet.Stagiaire.RejectChanges() Me.AfficherInformationsDataSetType() End Sub 3.3.3.8 Fermeture du formulaire Pour permettre la fermeture du formulaire au travers du bouton cliquer, implémentons l’évènement Click sur le bouton, et ajoutons l’instruction suivante : // C# private void CmdFermer_Click(object sender, EventArgs e) { // Fermeture du formulaire. this.Close(); } ' VB.NET Private Sub CmdFermer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdFermer.Click ' Fermeture du formulaire. Me.Close() End Sub Dotnet France Association – James RAVAILLE
21 Premiers pas avec Microsoft Synchronization Framework For ADO .NET 3.4 Exécution et test de l’application Nous pouvons maintenant exécuter cette application et nous obtenons l’IHM suivante : Nous exécutons alors les actions suivantes : 1 – Cliquons sur le bouton Synchroniser. Cette action a pour conséquence de mettre à jour notre base de données locale (DotnetFrance.sdf). Le DataSet typé est créé et alimenté avec les données, et les données affichées dans la grille. Si des modifications sont effectuées dans la base de données locale et/ou distante, alors les compteurs situés dans le haut du formulaire sont mis à jour. 2 – Nous modifions les données les données dans la grille : ajout d’un stagiaire, modification d’un autre stagiaire… On remarque que ces modifications sont comptabilisées. 3 – Ensuite, nous cliquons sur le bouton UP, ce qui a pour conséquences de mettre à jour la base de données locale, et de remettre les marqueurs associés à zéro. 4 – Puis on cliquer sur le bouton synchroniser, de manière à répercuter les modifications effectuées dans notre base de données locale dans la base de données distante, et vice-versa. Les modifications effectuées dans la base de données locale et/ou distante, alors les compteurs situés dans le haut du formulaire sont-elles mis à jour ? Nous remarquons que nos modifications ne sont pas uploadées ! Dotnet France Association – James RAVAILLE
22 Premiers pas avec Microsoft Synchronization Framework For ADO .NET Pas d’inquiétude : par défaut, la synchronisation n’est pas bi-directionnelle, mais uni-directionnelle dans le sens base de données distante vers la base de données locale. 3.5 Mise en œuvre de la synchronisation bi-directionnelle Le sens de la synchronisation peut être effectué : - Soit sur chaque table. - Soit sur chaque regroupement de table (syncGroup). Le sens de synchronisation est alors appliqué à toutes les tables du groupe. Dans notre cas, nous allons l’effectuer sur la table Stagiaire. Pour ce faire, une fois l’instance de la classe de synchronisation créée, on écrit l’instruction marquée en gras ci-dessus : // C# private void FrmGestionListeStagiaires_Load(object sender, EventArgs e) { oStagiaireTableAdapter = new StagiaireTableAdapter(); oDataSet = new SyncSourceDataSet(); oAgentSynchro = new clientSyncAgent(); oAgentSynchro.Stagiaire.SyncDirection = SyncDirection.Bidirectional; } ' VB.NET Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load oStagiaireTableAdapter = New StagiaireTableAdapter() oDataSet = New DotnetFranceDataSet() oAgentSynchro = New CompoSynchroSyncAgent() oAgentSynchro.Stagiaire.SyncDirection = SyncDirection.Bidirectional End Sub Si vous souhaitez centraliser la définition des sens de synchronisation au sein même du composant de synchronisation CompoSynchro.sync, pour ne la définir qu’une seule fois, vous devez vous positionner à la classe code-behind du composant de ce composant, et écrire l’instruction indiquée ci-dessous : // C# public partial class clientSyncAgent { partial void OnInitialized() { this.Stagiaire.SyncDirection = SyncDirection.Bidirectional; } } Dotnet France Association – James RAVAILLE
23 Premiers pas avec Microsoft Synchronization Framework For ADO .NET ' VB.NET Partial Public Class CompoSynchroSyncAgent Private Sub OnInitialized() Me.Stagiaire.SyncDirection = SyncDirection.Bidirectional End Sub End Class Remarque : pour utiliser l’énumération SyncDirection, importer l’espace de nom Microsoft.Synchronization.Data. Une fois la synchronisation bi-directionnelle mise en œuvre, réalisons l’exercice suivant : 1 – Lançons notre application, et synchronisons les données, de manière à les afficher. 2 – Modifions les données d’un stagiaire, et mettons à jour notre base de données locale. 3 – Sans fermer l’application, ouvrons SQL Server Management Studio, l’interface d’administration de SQL Server. Connectons-nous de manière à accéder à la base de données DotnetFrance. 4 – Ouvrons la table Stagiaire, et modifions les mêmes données du même enregistrement, avec d’autres valeurs. Que se passe-t-il ? Les données de la base de données locales, y compris les modifications, sont écrasées par les données de la base de données distantes. Il s’agit du fonctionnement par défaut du composant de synchronisation. Mais est-ce un fonctionnement qui répond à nos attentes ? Peut-être que dans certains cas, nous ne souhaitons pas écraser les données de la base de données locale ? Ainsi, sans règle fixe, nous souhaitons faire intervenir l’utilisateur, de manière à ce qu’il précise pour chacun des conflits de données détectés, quelle donnée fait foi. Pour ce faire, il est nécessaire d’apprendre à gérer les conflits de données. Dotnet France Association – James RAVAILLE
24 Premiers pas avec Microsoft Synchronization Framework For ADO .NET 4 Gestion des conflits de données 4.1 Présentation des cas de conflit de données Comme nous l’avons vu précédemment, une politique de gestion de conflits est nécessaire, de manière à résoudre les conflits de données, survenant lors des synchronisations de données. Dans notre cas, nous allons gérer le conflit de données suivant : un même donnée, a été modifiée à la fois dans la base de données distante, ainsi que dans la base de données locale. Pour traiter ce conflit, nous allons afficher une fenêtre à l’utilisateur, afin de présenter à l’utilisateur l’état des données en conflit de la base distantes, ainsi que les données correspondantes côté client. Il n’aura alors plus qu’à choisir les données à conserver. 4.2 Présentation du formulaire de gestion de conflits de données Voici l’IHM du formulaire que nous allons réaliser : L’ensemble des contrôles Textbox de ce formulaire ont leur propriété ReadOnly à True, de manière à ce que l’utilisateur ne puisse pas modifier les données. Ce formulaire sera affiché pour chaque conflit de données détecté, lors de la synchronisation des données concernant les stagiaires. Vous pouvez réaliser le design de ce formulaire. 4.3 Réalisation du formulaire de gestion de conflits de données Notre formulaire devra afficher les données contenu dans deux enregistrements en conflits (provenant de deux tables différentes). Dans le Framework .NET, les données d’un enregistrement peuvent être contenues un objet de type System.Data.DataRow. Pour gérer les données contenues dans ces deux enregistrements, nous définissons deus attributs de type DataRow , que nous initialisons dans le constructeur de la classe, comme indiqué ci-dessous : Dotnet France Association – James RAVAILLE
25 Premiers pas avec Microsoft Synchronization Framework For ADO .NET // C# public partial class FrmGestionConflitDonnees : Form { private DataRow StagiaireLocal; private DataRow StagiaireDistant; public FrmGestionConflitDonnees(DataRow aStagiaireLocal, DataRow aStagiaireDistant) { InitializeComponent(); // Initialisation des attributs. this.StagiaireLocal = aStagiaireLocal; this.StagiaireDistant = aStagiaireDistant; } } ' VB.NET Public Class FrmGestionConflitDonnees Private StagiaireLocal As DataRow Private StagiaireDistant As DataRow Public Sub New(ByVal aStagiaireLocal As DataRow, ByVal aStagiaireDistant As DataRow) ' Cet appel est requis par le Concepteur Windows Form. InitializeComponent() ' Initialisation des attributs. Me.StagiaireLocal = aStagiaireLocal Me.StagiaireDistant = aStagiaireDistant End Sub End Class Puis, nous allons afficher les données contenues dans nos DataRows dans les contrôles de l’IHM. Pour ce faire, nous allons implémenter l’évènement Load du formulaire : // C# private void FrmConflitDonnees_Load(object sender, EventArgs e) { // Affichage des informations. TxtNomLocal.Text = StagiaireLocal["Nom"].ToString(); TxtPrenomLocal.Text = StagiaireLocal["Prenom"].ToString(); TxtNomDistant.Text = StagiaireDistant["Nom"].ToString(); TxtPrenomDistant.Text = StagiaireDistant["Prenom"].ToString(); } Dotnet France Association – James RAVAILLE
26 Premiers pas avec Microsoft Synchronization Framework For ADO .NET ' VB.NET Private Sub FrmGestionConflitDonnees_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ' Affichage des informations. TxtNomLocal.Text = StagiaireLocal("Nom").ToString() TxtPrenomLocal.Text = StagiaireLocal("Prenom").ToString() TxtNomDistant.Text = StagiaireDistant("Nom").ToString() TxtPrenomDistant.Text = StagiaireDistant("Prenom").ToString() End Sub Puis, pour enregistrer au sein même du formulaire, le choix de l’utilisateur sur les données faisant foi, nous implémentons l’évènement Click sur les deux boutons, et fournissons l’implémentation suivante : // C# private void CmdChoisirDonneesDistantes_Click(object sender, EventArgs e) { this.DialogResult = DialogResult.No; } private void CmdChoisirDonneesLocales_Click(object sender, EventArgs e) { this.DialogResult = DialogResult.Yes; } ' VB.NET Private Sub CmdChoisirDonneesDistantes_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdChoisirDonneesDistantes.Click Me.DialogResult = DialogResult.No End Sub Private Sub CmdChoisirDonneesLocales_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdChoisirDonneesLocales.Click Me.DialogResult = DialogResult.Yes End Sub 4.4 Résolution des conflits de données Lors de la synchronisation des données, pour que ce formulaire soit affiché automatiquement si un conflit de données est rencontré, nous devons étendre la classe CompoSynchroServerSyncProvider en créant une classe partielle. Nous pouvons créer cette classe, dans la classe code-behind du composant de synchronisation CompoSynchro.sync. Dans cette classe, nous allons implémenter la méthode partielle OnInitialized. Dans cette méthode, nous nous abonnons à l’évènement ApplyChangeFailed. Nous obtenons alors le code suivant : Dotnet France Association – James RAVAILLE
27 Premiers pas avec Microsoft Synchronization Framework For ADO .NET // C# public partial class CompoSynchroServerSyncProvider { partial void OnInitialized() { this.ApplyChangeFailed += CompoSynchroServerSyncProvider_ApplyChangeFailed; } private void CompoSynchroServerSyncProvider_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { } } ' VB.NET Partial Public Class CompoSynchroServerSyncProvider Private Sub OnInitialized() AddHandler Me.ApplyChangeFailed, AddressOf CompoSynchroServerSyncProvider_ApplyChangeFailed End Sub Private Sub CompoSynchroServerSyncProvider_ApplyChangeFailed(ByVal sender As Object, ByVal e As ApplyChangeFailedEventArgs) End Sub End Class L’évènement ApplyChangeFailed est levé autant de fois que de conflits de données sont détectées. Dans le gestionnaire d’évènement CompoSynchroServerSyncProvider_ApplyChangeFailed, nous allons implémenter le traitement d’un conflit de données détectées : - Affichage modal du formulaire de gestion de conflits. Une fois que l’utilisateur clique sur un des boutons pour indiquer son choix, le formulaire se ferme. - En fonction de la valeur de la propriété DialogResult, on détermine sur quel bouton l’utilisateur a cliqué. Si la propriété DialogResult vaut DialogResult.Yes, alors les données de la base de données cliente concernant le stagiaire écrasent celles sur le serveur. Si la propriété DialogResult vaut DialogResult.No, alors les données de la base de données distante concernant le stagiaire écrasent celles dans la base de données cliente. L’action à réaliser est précisée au travers de l’attribut Action de l’argument du gestionnaire d’évènement : - Si nous précisions la valeur ApplyAction.RetryWithForceWrite, alors les données de la base de données distante sont mises à jour avec les données de la base de données locale. - Si nous précisions la valeur ApplyAction.Continue, alors les données de la base de données locale sont mises à jour avec les données de la base de données locale. Dotnet France Association – James RAVAILLE
28 Premiers pas avec Microsoft Synchronization Framework For ADO .NET // C# private void clientServerSyncProvider_ApplyChangeFailed(object sender, ApplyChangeFailedEventArgs e) { // Variables locales. DialogResult oResult; FrmConflitDonnees oFrmConflitStagiaire; if (e.Conflict.ConflictType == ConflictType.ClientUpdateServerUpdate) { oFrmConflitStagiaire = new FrmConflitDonnees( e.Conflict.ClientChange.Rows[0], e.Conflict.ServerChange.Rows[0]); oResult = oFrmConflitStagiaire.ShowDialog(); if (oResult == DialogResult.Yes) { e.Action = Microsoft.Synchronization.Data.ApplyAction.RetryWithForceWrite; } else { e.Action = Microsoft.Synchronization.Data.ApplyAction.Continue; } } } ' VB.NET Private Sub CompoSynchroServerSyncProvider_ApplyChangeFailed(ByVal sender As Object, ByVal e As ApplyChangeFailedEventArgs) ' Variables locales. Dim oResult As DialogResult Dim oFrmConflitStagiaire As FrmGestionConflitDonnees If e.Conflict.ConflictType = ConflictType.ClientUpdateServerUpdate Then oFrmConflitStagiaire = New FrmGestionConflitDonnees( _ e.Conflict.ClientChange.Rows(0), _ e.Conflict.ServerChange.Rows(0)) oResult = oFrmConflitStagiaire.ShowDialog() If (oResult = DialogResult.Yes) Then e.Action = Microsoft.Synchronization.Data.ApplyAction.RetryWithForceWrite Else e.Action = Microsoft.Synchronization.Data.ApplyAction.Continue End If End If End Sub Si nous exécutons de nouveau le même scénario que précédemment (modification du nom du stagiaire côté client en spécifiant EMATOU, et modification du nom du stagiaire côté serveur en spécifiant EMAT), la fenêtre suivante apparaît : Dotnet France Association – James RAVAILLE
29 Premiers pas avec Microsoft Synchronization Framework For ADO .NET En fonction du choix de l’utilisateur, les données seront mises à jour et synchronisées. Dotnet France Association – James RAVAILLE
Vous pouvez aussi lire