Globally Unique Identifiers... of GUIDs (uitgesproken als Geoduck met "uck" of als "Goe-id" voor mensen die het andere niet kunnen zeggen) zijn in principe uniek in tijd en ruimte. Ze worden gebruikt in COM en ze worden gebruikt in Jet-replicatie om een ID te creeren voor records die constant en uniek blijven ongeacht welke andere waarden (zoals sleutelwaarden) veranderen.
Veel mensen overwegen het idee om GUIDs te gebruiken voor hun primaire/referentiele sleutel, omdat ze uniciteit garanderen. Er zijn echter veel redenen om hier nog even bij stil te staan:
1) Als je in een applicatie een "ReplicatieID Autonummering-veld" (dwz een autonummering-GUID) gebruikt, die vervolgens tot replica wordt gemaakt, zal Jet jouw kolom gebruiken in plaats van een s_Guid-kolom te genereren. Helaas nemen de Conflict Resolver-wizard van Access 96 en 97 en de Conflict Viewer van Access 2000 aan dat er een s_Guid-kolom is. Conflictoplossing zal dus niet goed werken via de wizard, en je moet het zelf uitzoeken.
2) Een GUID wordt letterlijk opgeslagen als een 16-byte binaire waarde. Het heeft ook een canonieke (tekst-) vorm en een DAO/Jet-vorm, bestaande uit {guid {xxx}}, waar xxx de "canonieke" waarde is. Dit laatste formaat zal Jet altijd laten zien als je een select-statement uitvoert van een GUID-veld via DAO... de canonieke vorm wordt gebruikt als je direct via Jet gaat (als in Access-gegevensbladen) of ADO via de Jet OLE DB provider. Daarbij zijn de regels van DAO- versus ADO-filters, zoekopdrachten, Access-Domeinfuncties, Access-formulierfilters, links tussen formulier en subformulier, .Text versus .Value voor controls die zijn verbonden aan GUID-velden en alle zoekmethoden moeilijk te volgen en ze veranderen bij elke versie. Access heeft ingebouwde functies om de conversie tussen binaire en canonieke vorm te ondersteunen, namelijk StringFromGUID en GUIDFromString, maar zij gebruiken helaas de DAO-syntax, hoewel alles van COM en de meeste andere bronnen de voorkeur geven aan rechttoe rechtaan canoniek. Deze hele mengelmoes betekent dat het gebruiken van een GUID-veld voor deze operaties is als schieten op een bewegend doel.
3) De regels in #2 veranderen met elke versie en wijken bijna altijd af van de vorige versie. Daarom moet je in wezen al je werk opnieuw herzien bij elke upgrade.
4) Autonummers zijn vaak zichtbaar voor gebruikers, in voor- en tegenspoed. Dit is natuurlijk heel onpraktisch voor GUIDs, zelfs als het scala van minpunten met zoeken en zo geen echte problemen waren. GUIDs brengen gebruikers alleen maar in verwarring en niemand wil dat een GUID zich bekend maakt. :-)
Het is waar dat alle zaken die in #2 worden aangeduid, via verschillende technieken kunnen worden afgehandeld, waaronder:
1) Experimenteren met het gebruik van de echte canonieke vorm versus de {guid{xxx}}-canonieke vorm
2) Conversie via de twee Access-functies
3) CStr() gebruiken in de waarden van de velden in het SELECT-statement die GUIDs teruggeven zodat je het echte canonieke formaat krijgt
4) Alle plaatsen waar je iets wijzigt noteren, zodat je ze als/wanneer je upgrade weer kunt opzoeken (omdat de meeste in de volgende versie veranderd zullen zijn).
Je realiseren dat het onderliggende veld in het geval van DAO een dbGuid-type veld is en in het geval van ADO een adGuid-type... hoewel beide een veld van het type "tekst" teruggeven als je alleen maar kijkt naar de waarde. Dit toont nog maar eens aan hoe veel moeite ze allemaal doen om flexibel te lijken... dit is de belangrijkste reden waarom de zaken in #2 zo moeilijk te voorspellen zijn.
Hier zijn trouwens de niet-Access-functies om Guid/String en String/Guid-zaken uit te voeren als je werkt vanuit VB. Plak het in een module enzovoort.
Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type
Private Declare Function _
StringFromGUID2 Lib "ole32.dll" _
(rclsid As GUID, ByVal lpsz As Long, _
ByVal cbMax As Long) As Long
Private Declare Function _
CLSIDFromString Lib "ole32.dll" _
(pstCLS As Long, clsid As GUID) As Long
Function GuidFromStGuid(stGuid As String) As GUID
Call CLSIDFromString(ByVal StrPtr(stGuid), _
GuidFromStGuid)
End Function
Function StGuidFromGuid(rclsid As GUID) As String
Dim stGuid As String
Dim cch As Long
' 39 tekens voor de GUID plus ruimte voor het Null-teken
stGuid = String$(40, vbNullChar)
cch = StringFromGUID2(rclsid, StrPtr(stGuid), 39)
StGuidFromGuid = Left$(stGuid, cch)
End Function
LAATSTE AANBEVELING:
Het is wel mogelijk om de zaken in #2 en #3 te overkomen, maar #2 is zeer problematisch en heel moeilijk onderhoudbaar in het licht van #3. Het is in het algemeen de risico's van bugs en geforceerde upgrade-problemen niet waard. Er zijn betere manieren om primaire sleutels te kiezen die dergelijke problemen niet met zich mee brengen... dus het is bijna altijd aan te raden om die manieren te kiezen als je schone en makkelijk onderhoudbare database- en gerepliceerde applicaties wilt schrijven.
MichKa