Diese neue Tabelle bei der Jet 4.0 Replikation ist der Schlüssel zur Erstellung von mächtigen benutzerdefinierten Konfliktlösern. Die Info hier erklärt den Aufbau dieser Tabelle.
Zuerst beachten Sie, dass bei Jet 4.0 Konflikte an alle Replikate gemeldet werden, nicht wie bisher nur an das verlierende Replikat. Sie können das alte Schema verwenden, um Konflikte zu finden: die TableDefs-Collection durchlaufen, und jede Tabelle, bei der die ConflictTable-Eigenschaft auf einen Tabellennamen gesetzt ist, hat Konflikte. Aber das wäre viel mehr Arbeit als nötig. Stattdessen kann eine neue Tabelle namens MSysConflicts verwendet werden; sie beinhaltet Metadaten über *alle* Konflikte in der Datenbank.
Eine wichtige Änderung sind die "Kind-Konflikte", die passieren, wenn ein Divergenz-Konflikt (z.B. ein doppelter Primärschlüssel in der Angestellten-Tabelle) dafür sorgt, dass einige Bestellungen und Bestelldetails gelöscht werden, die mit dem verlierenden Angestellten-Datensatz zusammenhängen.
DER AUFBAU VON MSYSCONFLICTS:
Die erste Sache, die Ihnen auffallen wird, ist, dass das Jet-Team sich mit GUIDs vergnügt! Aber machen Sie sich nichts daraus; die meisten davon, betreffen Sie nicht und jene, die Sie betreffen, sind einfach, wenn Sie sie einmal verstanden haben.
-BaseGuidSrc - Eine GUID, die zum GuidSrc-Feld in MSysGenHistory linkt. Von Jet intern verwendet, um im Fall, dass in einer Zeile mehrere Konflikte mit mehreren Quellen auftreten, den zuletzt aufgetretenen Konflikt zu ermitteln. Normalerweise uninteressant für Anwender.
-BaseRowGuid - Eine GUID, die zum s_GUID-Feld in der Konflikt-Tabelle linkt. Sie repräsentiert den "Eltern"-Konflikt, daher enthalten alle Kind-Konflikte die gleiche BaseRowGuid als Eltern. Wenn sie übereinstimmt mit der ConflictIdGuid, dann handelt es sich um den Eltern-Konflikt.
-BaseTableGuid - Linkt zum s_GUID-Feld in MSysTableGuids und liefert Ihnen daher den Namen der Quelltabelle des Konflikts.
-ConflictDescCode - Konflikttyp - d.h. eindeutiger Schlüssel, TLV, simultanes Update, Fremdschlüssel etc.
-ConflictIdGuid - Eine GUID, die zum s_GUID-Feld in der Tabelle linkt. Wenn sie ident ist mit der BaseRowGuid, dann ist es der Eltern-Konflikt, sonst ist es ein Kind-Konflikt.
-InvolvedObjects - Ein Textfeld, dass Ihnen theoretisch Auskunft gibt, wo der Konflikt passierte, also Tabelle und Feld... in der Praxis habe ich noch nie gesehen, dass etwas drin stand.
-LosingReplicaId - Linkt zum s_GUID-Feld in MSysReplicas und sagt Ihnen, welches Replikat verloren hat.
-Reason - Text, der eine kontextsensitive Info über den Konflikt gibt, zur Anzeige gedacht.
-WinningGuidSrc - Linkt zum GuidSrc-Feld in MSysGenHistory. Wie BaseGuidSrc von Jet intern verwendet, um im Fall, dass in einer Zeile mehrere Konflikte mit mehreren Quellen auftreten, den zuletzt aufgetretenen Konflikt zu ermitteln. Normalerweise uninteressant für Anwender.
-WinningReplicaId - Linkt zum s_GUID-Feld in MSysReplicas und sagt Ihnen, welches Replikat gewonnen hat.
-WinningRowGuid - Linkt zum s_GUID-Feld der Quelltabelle, wenn es noch eine Quellzeile gibt, auf die Sie sich beziehen möchten (wie z.B. in einem Update-Update-Konflikt oder in einem Konflikt wegen doppelter Primärschlüssel).
-s_GUID - Replikations-Systemfeld... linkt zum ConflictRowGuid in der Konflikttabelle, wenn Sie den Link brauchen.
-s_Generation - Replikations-Systemfeld...
-s_Lineage - Replikations-Systemfeld....
OK... gehen wir mal davon aus, sie möchten folgendes machen:
1) Alle Eltern-Konflikte auflisten, aber keine Kind-Konflikte
2) Die verlierenden und gewinnenden Replikate anzeigen
3) Die Anzahl der Konflikte und die Anzahl der Kind-Konflikte anzeigen
4) Den Namen der Konflikttabelle anzeigen und den der Quelltabelle
Sie könnten das alles mit einer Abfrage wie der folgenden machen:
SELECT
Max(tg.TableName) AS src_Table,
Max(st.SideTable) AS conflict_table,
Count(IIF(c_a.ConflictIdGuid <> c_a.s_Guid,Null, 1)) As CnfCount,
Count(IIF(c_a.ConflictIdGuid = c_a.s_Guid, Null, 1)) As
CnfChildCount
FROM
(((MSysTableGuids AS tg INNER JOIN
MSysSideTables AS st ON tg.s_GUID = st.TableGuid) INNER
JOIN
MSysConflicts AS c ON st.TableGuid = c.BaseTableGuid)
INNER JOIN
MSysReplicas AS r ON c.WinningReplicaId = r.ReplicaId)
INNER JOIN
MSysConflicts AS c_a ON c_a.ConflictIdGuid = c.s_Guid
WHERE
c.ConflictIDGuid = c.s_Guid
GROUP BY
tg.TableName;
Das gibt ein hübsches Ergebnis mit allen Quell- und Konflikttabellen, ebenso die Anzahl der Konflikte und der dazugehörigen Kind-Konflikte. Und wenn Sie durch die Konflikte scrollen und die kompletten Quell- und Konfliktspalten z.B. für die Tabelle Customers in ein einziges Recordset bekommen möchten:
SELECT
Customers.*,
Customers_Conflict.*
FROM
(Customers_Conflict INNER JOIN
MSysConflicts ON Customers_Conflict.ConflictRowGuid = MSysConflicts.s_GUID) LEFT JOIN
Customers ON MSysConflicts.WinningRowGuid = Customers.s_GUID
Von dort brauchen Sie die Info nur noch abzuholen...
Zu dem Thema wird mit der Zeit sicher noch mehr kommen, aber zuerst einmal den Aufbau durchzugehen schien mit ein guter erster Schritt.