You are here: Implementation Strategies > IDs And UUIDs > Unique Universal IDs

Unique Universal IDs

For long-term external references and to identify an object even after it has been copied or moved to another IObjectContainer, 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#:

LocalObjectContainer#GenerateNewIdentity

VB: LocalObjectContainer#GenerateNewIdentity

method.

UUIDExample.cs: TestChangeIdentity
private static void TestChangeIdentity()
     {
      File.Delete(Db4oFileName);
      IObjectContainer container = Db4oFactory.OpenFile(Db4oFileName);
      Db4oDatabase db;
      byte[] oldSignature;
      byte[] newSignature;
      try 
       {
        db = container.Ext().Identity();
        oldSignature = db.GetSignature();
        Console.WriteLine("oldSignature: " + PrintSignature(oldSignature));
                ((LocalObjectContainer)container).GenerateNewIdentity();
      } 
      finally 
       {
        container.Close();
      }        
      container = Db4oFactory.OpenFile(Db4oFileName);
      try 
       {
        db = container.Ext().Identity();
        newSignature = db.GetSignature();
        Console.WriteLine("newSignature: " + PrintSignature(newSignature));
      } 
      finally 
       {
        container.Close();
      }
        
      bool same = true;
        
      for (int i = 0; i < oldSignature.Length; i++) 
       {
        if(oldSignature[i] != newSignature[i])
         {
          same =false;
        }
      }
        
      if (same)
       {
        Console.WriteLine("Database signatures are identical");
      } 
      else 
       {
        Console.WriteLine("Database signatures are different");
      }
    }

UUIDExample.vb: TestChangeIdentity
Public Shared Sub TestChangeIdentity()

            File.Delete(Db4oFileName)
            Dim container As IObjectContainer = Db4oFactory.OpenFile(Db4oFileName)
            Dim db As Db4oDatabase
            Dim oldSignature() As Byte
            Dim NewSignature() As Byte
            Try
                db = container.Ext().Identity()
                oldSignature = db.GetSignature()
                Console.WriteLine("oldSignature: " + _ 
PrintSignature(oldSignature))
                Dim yf As LocalObjectContainer = _ 
DirectCast(container, LocalObjectContainer)
                yf.GenerateNewIdentity()
            Finally
                container.Close()
            End Try
            container = Db4oFactory.OpenFile(Db4oFileName)
            Try
                db = container.Ext().Identity()
                NewSignature = db.GetSignature()
                Console.WriteLine("newSignature: " + _ 
PrintSignature(NewSignature))
            Finally
                container.Close()
            End Try

            Dim same As Boolean = True

            Dim i As Integer
            For i = 0 To oldSignature.Length - 1 Step i + 1
                If oldSignature(i) <> NewSignature(i) Then

                    same = False
                End If
            Next

            If (same) Then
                Console.WriteLine("Database signatures are identical")
            Else
                Console.WriteLine("Database signatures are different")
            End If
        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#: configuration.GenerateUUIDs(ConfigScope.Globally)

VB: configuration.GenerateUUIDs(ConfigScope.Globally)

- turns on UUID generation for all classes in a database.

c#:configuration.ObjectClass(typeof(Foo)).GenerateUUIDs(true)

VB:configuration.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:

UUIDExample.cs: SetObjects
private static void SetObjects()
     {
            File.Delete(Db4oFileName);
            IConfiguration configuration = Db4oFactory.NewConfiguration();
            configuration.ObjectClass(typeof(Pilot)).GenerateUUIDs(true);
            IObjectContainer container = Db4oFactory.
OpenFile(configuration, Db4oFileName);
      try 
       {
        Car car = new Car("BMW", new Pilot("Rubens Barrichello"));
        container.Store(car);
      } 
      finally 
       {
        container.Close();
      }
    }

UUIDExample.vb: SetObjects
Public Shared Sub SetObjects()
            File.Delete(Db4oFileName)
            Dim configuration As IConfiguration = Db4oFactory.NewConfiguration
            configuration.ObjectClass(GetType(Pilot)).GenerateUUIDs(True)
            Dim container As IObjectContainer = _ 
Db4oFactory.OpenFile(configuration, Db4oFileName)
            Try
                Dim car As Car = New Car("BMW", New Pilot("Rubens Barrichello"))
                container.Store(car)
            Finally
                container.Close()
            End Try
        End Sub

UUIDExample.cs: TestGenerateUUID
private static void TestGenerateUUID()
     {
      IObjectContainer container = Db4oFactory.OpenFile(Db4oFileName);
      try 
       {
        IQuery query = container.Query();
        query.Constrain(typeof(Car));
        IObjectSet result = query.Execute();
        Car car = (Car)result[0];
        IObjectInfo carInfo = container.Ext().GetObjectInfo(car);
        Db4oUUID carUUID = carInfo.GetUUID();
        Console.WriteLine("UUID for Car class are not generated:");
        Console.WriteLine("Car UUID: " + carUUID);
      
        Pilot pilot = car.Pilot;
        IObjectInfo pilotInfo = container.Ext().GetObjectInfo(pilot);
        Db4oUUID pilotUUID = pilotInfo.GetUUID();
        Console.WriteLine("UUID for Car class are not generated:");
        Console.WriteLine("Pilot UUID: " + pilotUUID);
        Console.WriteLine("long part: " + pilotUUID.GetLongPart() +
"; signature: " + PrintSignature(pilotUUID.GetSignaturePart()));
        long ms = TimeStampIdGenerator.IdToMilliseconds(pilotUUID.GetLongPart());
        Console.WriteLine("Pilot object was created: " + 
(new DateTime(1970,1,1)).AddMilliseconds(ms).ToString());
        Pilot pilotReturned = (Pilot)container.Ext().GetByUUID(pilotUUID);
        Console.WriteLine("Pilot from UUID: " + pilotReturned);  
      } 
      finally 
       {
        container.Close();
      }        
    }

UUIDExample.vb: TestGenerateUUID
Public Shared Sub TestGenerateUUID()
            Dim container As IObjectContainer = Db4oFactory.OpenFile(Db4oFileName)
            Try
                Dim query As IQuery = container.Query()
                query.Constrain(GetType(car))
                Dim result As IObjectSet = query.Execute()
                Dim car As Car = CType(result(0), Car)
                Dim carInfo As IObjectInfo = container.Ext().GetObjectInfo(car)
                Dim carUUID As Db4oUUID = carInfo.GetUUID()
                Console.WriteLine("UUID for Car class are not generated:")
                If carUUID Is Nothing Then
                    Console.WriteLine("Car UUID: null")
                Else
                    Console.WriteLine("Car UUID: " + carUUID.ToString())
                End If


                Dim pilot As Pilot = car.Pilot
                Dim pilotInfo As IObjectInfo = container.Ext().GetObjectInfo(pilot)
                Dim pilotUUID As Db4oUUID = pilotInfo.GetUUID()
                Console.WriteLine("UUID for Car class are not generated:")
                If pilotUUID Is Nothing Then
                    Console.WriteLine("Pilot UUID: null")
                Else
                    Console.WriteLine("Pilot UUID: " + pilotUUID.ToString())
                End If

                Console.WriteLine("long part: " + _ 
pilotUUID.GetLongPart().ToString() + "; signature: " + _ 
PrintSignature(pilotUUID.GetSignaturePart()))
                Dim ms As Long = TimeStampIdGenerator.IdToMilliseconds( _ 
pilotUUID.GetLongPart())
                Console.WriteLine("Pilot object was created: " + _ 
(New DateTime(1970, 1, 1)).AddMilliseconds(ms).ToString())
                Dim pilotReturned As Pilot = CType(container.Ext(). _ 
GetByUUID(pilotUUID), Pilot)
                Console.WriteLine("Pilot from UUID: " + pilotReturned.ToString())
            Finally
                container.Close()
            End Try
        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#:

configuration.ObjectClass(typeof(Task)).EnableReplication(true)

vb:

configuration.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.

Download example code:

VB.NET c#