Synchronisation sans replication.
1. Le système utilise des nombres aléatoires "autonumber" pour
éviter les possibilités de duplication de clé. Chaque enregistrement possède
également un champ DateLastUpdated qui est assigné à Now() lors de
chaque changement dans l'enregistrement, à une précision de une seconde. La
synchronisation repose donc sur deux conditions: si une clé n'est pas trouvée
dans la table du Master, l'enregistrement du Replica est ajouté à la table du
Master comme nouvel enregistrement; si la clé est trouvée et que DateLastChanged
du Replica est la même que sur le Master, alors on ne fait rien avec
l'enregistrement du Replica. Si les dates sont différentes, l'utilisateur voit
les deux champs, du Master et du Replica, côte à côte, pour prendre une
décision sur lequel conserver et lequel rejeter. Au cours de ce
processus, frmDifferences est éditable, et l'opérateur peut donc
effectuer les changements appropriés avant d'accepter une ou l'autre des
versions.
2. Le formulaire frmDifferences est un formulaire générique de trois colonnes,
la première étant l'étiquette du champ (pour être significative à
l'utilisateur), la seconde est le contenu du Master, la troisième, celle du Replica.
Si le champ est un Combo ou List box, la valeur est représentée par une zone
de liste avec les valeurs choisies.
3. Le système comporte trois étapes:
a) Lier les tables du Replica au Maître. Ceci crée des
table en double avec un 1 ajouté à la fin du nom (mais un autre caractère
peut être utilisé).
b) Traverse chaque table en utilisant l'algorithme
précédant pour présenter à l'utilisateur les cas requérant une intervention.
c) Effacer les tables du Replica du Master. On peut
maintenant se débarrasser du Replica pour le remplacer par le Master afin de
repartir le processus à nouveau.
[Cette dernière étape peut également être
automatisée, mais mon client ne désirait pas dépenser l'argent.]
Vous pouvez ajouter le traitement d'erreur pour rendre le tout plus robuste,
mais la situation actuelle était satisfaisante pour mon client.
Le code doit être adapté pour chaque cas. Ce n'est applicable que pour de
petites applications seulement. Il fonctionne virtuellement sans overhead (ce
qui n'est pas du tout le cas avec la replication standard) dans notre cas,
puisqu'il n'utilise qu'une clé et un champ daté.
Il est possible, pour des enregistrement, de générer la même clé, ou
d'être modifié exactement à la même seconde. Le risque est minimal et
tolérable, dans notre cas.
Une synchronisation hebdomadaire prends moins de cinq minutes et
l'utilisateur est en complet contrôle du processus.
Private Sub cmdSynchronise_Click()
If Not LinkReplica() Then
MsgBox "Replica not linked correctly. Contact Programmer"
DoCmd.Quit
End If
MsgBox "Link with replica completed, synchronisation started"
DoCmd.Hourglass True
SyncCategories
SyncConsultants
SyncDepartments
SyncSponsors
SyncStages
SyncJobs
SyncComments
SyncJobConsultants
SyncJobSponsors
DoCmd.Hourglass False
MsgBox "Synchronisation completed, unlink replica"
If Not UnLinkReplica() Then
MsgBox "Replica not unlinked correctly. Contact Programmer"
DoCmd.Quit
End If
MsgBox "Replica unlinked. Destroy replica and replace with copy of"
master ""
End Sub
Private Sub SyncCategories()
InitialiseDifferences
XTable = "Categories"
Set dbs = CurrentDb()
Set master = dbs.OpenRecordset("tbl" & XTable, dbOpenDynaset)
Set replica = dbs.OpenRecordset("tbl" & XTable & "1", dbOpenDynaset)
replica.MoveFirst
While Not replica.EOF
master.FindFirst "CategoryID = " & replica!CategoryID
If master.NoMatch Then
master.AddNew
master!CategoryID = replica!CategoryID
master!Description = replica!Description
master!DateLastChanged = replica!DateLastChanged
master.Update
MsgBox "New category added = " & replica!Description
Else
If replica!DateLastChanged <> master!DateLastChanged Then
XLabel1 = "Description"
MField1 = master!Description
RField1 = replica!Description
DoCmd.OpenForm "frmDifferences", , , , , acDialog
master.Edit
master!Description = MField1
master!DateLastChanged = Now()
master.Update
End If
End If
replica.MoveNext
Wend
replica.Close
master.Close
Set master = Nothing
Set rst = Nothing
Set dbs = Nothing
End Sub
Private Sub SyncSponsors()
InitialiseDifferences
XTable = "Sponsors"
Set dbs = CurrentDb()
Set master = dbs.OpenRecordset("tbl" & XTable, dbOpenDynaset)
Set replica = dbs.OpenRecordset("tbl" & XTable & "1", dbOpenDynaset)
replica.MoveFirst
While Not replica.EOF
master.FindFirst "SponsorID = " & replica!SponsorID
If master.NoMatch Then
master.AddNew
master!SponsorID = replica!SponsorID
master!DepartmentID = replica!DepartmentID
master!Title = replica!Title
master!Name = replica!Name
master!Phone = replica!Phone
master!Location = replica!Location
master!DateLastChanged = replica!DateLastChanged
master.Update
MsgBox "New Sponsor added = " & replica!Name
Else
If replica!DateLastChanged <> master!DateLastChanged Then
XLabel1 = "Title"
MField1 = master!Title
RField1 = replica!Title
XLabel2 = "Name"
MField2 = master!Name
RField2 = replica!Name
XLabel3 = "Phone"
MField3 = master!Phone
RField3 = replica!Phone
XLabel4 = "Location"
MField4 = master!Location
RField4 = replica!Location
XLabel6 = "Department"
MCombo6 = master!DepartmentID
RCombo6 = replica!DepartmentID
DoCmd.OpenForm "frmDifferences", , , , , acDialog
master.Edit
master!Title = MField1
master!Name = MField2
master!Phone = MField3
master!Location = MField4
master!DepartmentID = MCombo6
master!DateLastChanged = Now()
master.Update
End If
End If
replica.MoveNext
Wend
replica.Close
master.Close
Set master = Nothing
Set rst = Nothing
Set dbs = Nothing
End Sub
frmDifferencescode
Option Compare Database
Option Explicit
Private Sub cmdMaster_Click()
On Error GoTo Err_cmdMaster_Click
MField1 = Me!fmField1
MField2 = Me!fmField2
MField3 = Me!fmField3
MField4 = Me!fmField4
MField5 = Me!fmField5
If XLabel6 <> "" Then MCombo6 = Me!fMCombo6
If XLabel7 <> "" Then MCombo7 = Me!fMCombo7
DoCmd.Close
Exit_cmdMaster_Click:
Exit Sub
Err_cmdMaster_Click:
MsgBox Err.Description
Resume Exit_cmdMaster_Click
End Sub
Private Sub cmdReplica_Click()
On Error GoTo Err_cmdReplica_Click
MField1 = Me!frField1
MField2 = Me!frField2
MField3 = Me!frField3
MField4 = Me!frField4
MField5 = Me!frField5
If XLabel6 <> "" Then MCombo6 = Me!fRCombo6
If XLabel7 <> "" Then MCombo7 = Me!fRCombo7
DoCmd.Close
Exit_cmdReplica_Click:
Exit Sub
Err_cmdReplica_Click:
MsgBox Err.Description
Resume Exit_cmdReplica_Click
End Sub
Private Sub Form_Load()
Me!fXTable = XTable
Me!fLabel1 = XLabel1
Me!fmField1 = MField1
Me!frField1 = RField1
Me!fLabel2 = XLabel2
Me!fmField2 = MField2
Me!frField2 = RField2
Me!fLabel3 = XLabel3
Me!fmField3 = MField3
Me!frField3 = RField3
Me!fLabel4 = XLabel4
Me!fmField4 = MField4
Me!frField4 = RField4
Me!fLabel5 = XLabel5
Me!fmField5 = MField5
Me!frField5 = RField5
Me!fLabel6 = XLabel6
If XLabel6 <> "" Then
SetComboBox6
End If
Me!fLabel7 = XLabel7
If XLabel7 <> "" Then
SetComboBox7
End If
End Sub
Private Sub SetComboBox6()
Select Case XLabel6
Case "Department"
Me.RecordSource = "tblDepartments"
fMCombo6.DefaultValue = MCombo6
fMCombo6.RowSource = "SELECT DISTINCTROW [tblDepartments].[DepartmentID], " & _
"[tblDepartments].[Branch], [tblDepartments].[ShortDepartment] " & _
"FROM [tblDepartments];"
fMCombo6.ColumnCount = 3
fMCombo6.ColumnWidths = "0cm;3.8cm;0.75cm"
fMCombo6.BoundColumn = 1
fRCombo6.DefaultValue = RCombo6
fRCombo6.RowSource = "SELECT DISTINCTROW [tblDepartments].[DepartmentID], " & _
"[tblDepartments].[Branch], [tblDepartments].[ShortDepartment] " & _
"FROM [tblDepartments];"
fRCombo6.ColumnCount = 3
fRCombo6.ColumnWidths = "0cm;3.8cm;0.75cm"
fRCombo6.BoundColumn = 1
Case "Category"
Me.RecordSource = "tblCategories"
fMCombo6.DefaultValue = MCombo6
fMCombo6.RowSource = "SELECT DISTINCTROW [tblCategories].[CategoryID], " & _
"[tblCategories].[Description] FROM [tblCategories];"
fMCombo6.ColumnCount = 2
fMCombo6.ColumnWidths = "0cm;4.55cm"
fMCombo6.BoundColumn = 1
fRCombo6.DefaultValue = RCombo6
fRCombo6.RowSource = "SELECT DISTINCTROW [tblCategories].[CategoryID], " & _
"[tblCategories].[Description] FROM [tblCategories];"
fRCombo6.ColumnCount = 2
fRCombo6.ColumnWidths = "0cm;4.55cm"
fRCombo6.BoundColumn = 1
Case "Stage"
Me.RecordSource = "tblStages"
fMCombo6.DefaultValue = MCombo6
fMCombo6.RowSource = "SELECT tblStages.StageID, tblStages.Description " & _
"FROM tblStages ORDER BY tblStages.SortOrder;"
fMCombo6.ColumnCount = 2
fMCombo6.ColumnWidths = "0cm;4.55cm"
fMCombo6.BoundColumn = 1
fRCombo6.DefaultValue = RCombo6
fRCombo6.RowSource = "SELECT tblStages.StageID, tblStages.Description " & _
"FROM tblStages ORDER BY tblStages.SortOrder;"
fRCombo6.ColumnCount = 2
fRCombo6.ColumnWidths = "0cm;4.55cm"
fRCombo6.BoundColumn = 1
Case Else
End Select
End Sub
Public Function LinkReplica()
On Error GoTo LinkReplica_Err
Dim tdf As TableDef
Dim strTable As String
Dim strNewConnect As String
Set dbs = CurrentDb()
Set rst = dbs.OpenRecordset("SELECT MSysObjects.Connect, MsysObjects.Database, " & _
"MSysObjects.Name from MSysObjects " & _
"WHERE MSysObjects.Type = " & IntAttachedTableType)
rst.MoveLast
If rst.RecordCount <> 0 Then
rst.MoveFirst
strNewConnect = ";DATABASE=" & strDataReplica
While Not rst.EOF
strTable = rst!Name
Set tdf = dbs.CreateTableDef(strTable & "1")
tdf.Connect = strNewConnect
tdf.SourceTableName = strTable
dbs.TableDefs.Append tdf
Set tdf = Nothing
rst.MoveNext
Wend
End If
dbs.TableDefs.Refresh
rst.Close
Set rst = Nothing
LinkReplica = True
Set dbs = Nothing
Exit Function
LinkReplica_Err:
LinkReplica = False
MsgBox "Replica not linked, Contact programmer"
End Function
Public Function UnLinkReplica()
On Error GoTo UnLinkReplica_Err
Dim tdf As TableDef
Dim strTable As String
Set dbs = CurrentDb()
Set rst = dbs.OpenRecordset("SELECT MSysObjects.Connect, MsysObjects.Database, " & _
"MSysObjects.Name from MSysObjects " & _
"WHERE MSysObjects.Type = " & IntAttachedTableType)
rst.MoveLast
If rst.RecordCount <> 0 Then
rst.MoveFirst
While Not rst.EOF
strTable = rst!Name
If right(strTable, 1) = "1" Then
dbs.TableDefs.Delete (strTable)
End If
rst.MoveNext
Wend
End If
dbs.TableDefs.Refresh
rst.Close
Set rst = Nothing
UnLinkReplica = True
Set dbs = Nothing
Exit Function
LinkReplica_Err:
UnLinkReplica = False
MsgBox "Replica not unlinked, Contact programmer"
End Function