For long-term external references and to identify an object even after it has been copied or moved to another ObjectContainer, db4o supplies Unique Universal IDs (UUIDs).
Every newly created db4o database generates a signature object. It is stored as an instance of Db4oDatabase in your database file.
This signature is linked to all newly created objects (if UUID generation is enabled) as the "signature part" of the UUID.
Further to that db4o creates a timestamp for every new object and uses an internal counter to make sure that timestamps are unique. This is called the "long part" of the UUID.
The long part is indexed to make the search fast. If two objects with an identical long parts are found, the signature parts are compared also.
The long part of the UUID can also be used to find out when an object was created. You can use
c#:Db4objects.Db4o.Foundation.TimeStampIdGenerator#IdToMilliseconds()
VB:Db4objects.Db4o.Foundation.TimeStampIdGenerator#IdToMilliseconds()
to get object creation time in milliseconds.
UUIDs are guaranteed to be unique, if the signature of your db4o database is unique.
Normally any database has a unique signature unless its file is copied. The original and copied database files are identical, so they have the same signatures. If such files are used in replication, the process will end up with exceptions. What is the solution then?
Signature of a database file can be changed using
c#: YapFile#GenerateNewIdentity
VB: YapFile#GenerateNewIdentity
01public static void TestChangeIdentity() 02
{ 03
File.Delete(YapFileName); 04
IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 05
Db4oDatabase db; 06
byte[] oldSignature; 07
byte[] newSignature; 08
try 09
{ 10
db = oc.Ext().Identity(); 11
oldSignature = db.GetSignature(); 12
Console.WriteLine("oldSignature: " + PrintSignature(oldSignature)); 13
((LocalObjectContainer)oc).GenerateNewIdentity(); 14
} 15
finally 16
{ 17
oc.Close(); 18
} 19
oc = Db4oFactory.OpenFile(YapFileName); 20
try 21
{ 22
db = oc.Ext().Identity(); 23
newSignature = db.GetSignature(); 24
Console.WriteLine("newSignature: " + PrintSignature(newSignature)); 25
} 26
finally 27
{ 28
oc.Close(); 29
} 30
31
bool same = true; 32
33
for (int i = 0; i < oldSignature.Length; i++) 34
{ 35
if(oldSignature[i] != newSignature[i]) 36
{ 37
same =false; 38
} 39
} 40
41
if (same) 42
{ 43
Console.WriteLine("Database signatures are identical"); 44
} 45
else 46
{ 47
Console.WriteLine("Database signatures are different"); 48
} 49
}
01Public Shared Sub TestChangeIdentity() 02
03
File.Delete(YapFileName) 04
Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 05
Dim db As Db4oDatabase 06
Dim oldSignature() As Byte 07
Dim NewSignature() As Byte 08
Try 09
db = oc.Ext().Identity() 10
oldSignature = db.GetSignature() 11
Console.WriteLine("oldSignature: " + PrintSignature(oldSignature)) 12
Dim yf As LocalObjectContainer = DirectCast(oc, LocalObjectContainer) 13
yf.GenerateNewIdentity() 14
Finally 15
oc.Close() 16
End Try 17
oc = Db4oFactory.OpenFile(YapFileName) 18
Try 19
db = oc.Ext().Identity() 20
NewSignature = db.GetSignature() 21
Console.WriteLine("newSignature: " + PrintSignature(NewSignature)) 22
Finally 23
oc.Close() 24
End Try 25
26
Dim same As Boolean = True 27
28
Dim i As Integer 29
For i = 0 To oldSignature.Length - 1 Step i + 1 30
If oldSignature(i) <> NewSignature(i) Then 31
32
same = False 33
End If 34
Next 35
36
If (same) Then 37
Console.WriteLine("Database signatures are identical") 38
Else 39
Console.WriteLine("Database signatures are different") 40
End If 41
End Sub
UUIDs are not generated by default, since they occupy extra space in the database file and produce performance overhead for maintaining their index. UUIDs can be turned on globally or for individual classes:
c#: Db4oFactory.Configure().GenerateUUIDs(Int32.MaxValue)
VB: Db4oFactory.Configure().GenerateUUIDs(Int32.MaxValue)
- turns on UUID generation for all classes in a database.
c#:Db4oFactory.Configure().ObjectClass(typeof(Foo)).GenerateUUIDs(true)
VB:Db4oFactory.Configure().ObjectClass(GetType(Foo)).GenerateUUIDs(true)
- turns on UUID generation for a specific class.
You can get the UUID value for an object using the following methods:
c#:
IEExtObjectContainer#GetObjectInfo(Object)
IObjectInfo#GetUUID()
VB:
IExtObjectContainer#GetObjectInfo(Object)
IObjectInfo#GetUUID()
To get the object from the database, knowing its UUID, use:
c#:IExtObjectContainer#GetByUUID(Db4oUUID)
vb: IExtObjectContainer#GetByUUID(Db4oUUID)
The following example shows the usage of UUID:
01public static void SetObjects() 02
{ 03
Db4oFactory.Configure().ObjectClass(typeof(Pilot)).GenerateUUIDs(true); 04
File.Delete(YapFileName); 05
IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 06
try 07
{ 08
Car car = new Car("BMW", new Pilot("Rubens Barrichello")); 09
oc.Set(car); 10
} 11
finally 12
{ 13
oc.Close(); 14
} 15
}
01Public Shared Sub SetObjects() 02
Db4oFactory.Configure().ObjectClass(GetType(Pilot)).GenerateUUIDs(True) 03
File.Delete(YapFileName) 04
Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 05
Try 06
Dim car As Car = New Car("BMW", New Pilot("Rubens Barrichello")) 07
oc.Set(car) 08
Finally 09
oc.Close() 10
End Try 11
End Sub
01public static void TestGenerateUUID() 02
{ 03
IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 04
try 05
{ 06
IQuery query = oc.Query(); 07
query.Constrain(typeof(Car)); 08
IObjectSet result = query.Execute(); 09
Car car = (Car)result[0]; 10
IObjectInfo carInfo = oc.Ext().GetObjectInfo(car); 11
Db4oUUID carUUID = carInfo.GetUUID(); 12
Console.WriteLine("UUID for Car class are not generated:"); 13
Console.WriteLine("Car UUID: " + carUUID); 14
15
Pilot pilot = car.Pilot; 16
IObjectInfo pilotInfo = oc.Ext().GetObjectInfo(pilot); 17
Db4oUUID pilotUUID = pilotInfo.GetUUID(); 18
Console.WriteLine("UUID for Car class are not generated:"); 19
Console.WriteLine("Pilot UUID: " + pilotUUID); 20
Console.WriteLine("long part: " + pilotUUID.GetLongPart() +"; signature: " + PrintSignature(pilotUUID.GetSignaturePart())); 21
long ms = TimeStampIdGenerator.IdToMilliseconds(pilotUUID.GetLongPart()); 22
Console.WriteLine("Pilot object was created: " + (new DateTime(1970,1,1)).AddMilliseconds(ms).ToString()); 23
Pilot pilotReturned = (Pilot)oc.Ext().GetByUUID(pilotUUID); 24
Console.WriteLine("Pilot from UUID: " + pilotReturned); 25
} 26
finally 27
{ 28
oc.Close(); 29
} 30
}
01Public Shared Sub TestGenerateUUID() 02
Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 03
Try 04
Dim query As IQuery = oc.Query() 05
query.Constrain(GetType(car)) 06
Dim result As IObjectSet = query.Execute() 07
Dim car As Car = CType(result(0), Car) 08
Dim carInfo As IObjectInfo = oc.Ext().GetObjectInfo(car) 09
Dim carUUID As Db4oUUID = carInfo.GetUUID() 10
Console.WriteLine("UUID for Car class are not generated:") 11
If carUUID Is Nothing Then 12
Console.WriteLine("Car UUID: null") 13
Else 14
Console.WriteLine("Car UUID: " + carUUID.ToString()) 15
End If 16
17
18
Dim pilot As Pilot = car.Pilot 19
Dim pilotInfo As IObjectInfo = oc.Ext().GetObjectInfo(pilot) 20
Dim pilotUUID As Db4oUUID = pilotInfo.GetUUID() 21
Console.WriteLine("UUID for Car class are not generated:") 22
If pilotUUID Is Nothing Then 23
Console.WriteLine("Pilot UUID: null") 24
Else 25
Console.WriteLine("Pilot UUID: " + pilotUUID.ToString()) 26
End If 27
28
Console.WriteLine("long part: " + pilotUUID.GetLongPart().ToString() + "; signature: " + PrintSignature(pilotUUID.GetSignaturePart())) 29
Dim ms As Long = TimeStampIdGenerator.IdToMilliseconds(pilotUUID.GetLongPart()) 30
Console.WriteLine("Pilot object was created: " + (New DateTime(1970, 1, 1)).AddMilliseconds(ms).ToString()) 31
Dim pilotReturned As Pilot = CType(oc.Ext().GetByUUID(pilotUUID), Pilot) 32
Console.WriteLine("Pilot from UUID: " + pilotReturned.ToString()) 33
Finally 34
oc.Close() 35
End Try 36
End Sub
Sometimes you can find out that you need UUIDs only when the database is already created and has some data in it. What can you do in that case?
Fortunately enabling replication for existing data files is a very simple process:
c#:Db4oFactory.Configure().ObjectClass(typeof(Task)).EnableReplication(true)
vb: Db4oFactory.Configure().ObjectClass(GetType(Task)).EnableReplication(true)
After that you will just need to use the old defragment tool from tools package supplied with the distribution before version 6.0 (source code only) to enable replication.
You can use UUID for replication and as a reference to a specific object instance from an external application or data store.