Refactoring API

Db4o provides special API which can help you to move classes between packages (Java)/namespaces(.NET), rename classes or fields:

c#:
Db4oFactory.Configure().ObjectClass("package.class").Rename("newPackage.newClass")
Db4oFactory.Configure().ObjectClass("package.class").ObjectField("oldField").Rename("newField")

VB:
Db4oFactory.Configure().ObjectClass("package.class").Rename("newPackage.newClass")
Db4oFactory.Configure().ObjectClass("package.class").ObjectField("oldField").Rename("newField")

The safe order of actions for rename calls is:

  1. Backup you database and aaplication
  2. Close all open objectContainers if any
  3. Rename classes or fields or copy classes to the new package/namespace in your application. (Do not remove old classes yet).
  4. Issue ObjectClass#rename and objectField#rename calls without having an ObjectContainer open.
  5. Open database file and close it again without actually working with it.
  6. Remove old classes (if applicable).

After that you will only see the new classes/fields in ObjectManager, the old ones will be gone.

Let's look how it works on an example. We will use initial class Pilot:

Pilot.cs
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02using System; 03 04namespace Db4objects.Db4odoc.Refactoring 05{ 06 public class Pilot 07 { 08 private string _name; 09 10 public Pilot(string name) 11 { 12 this._name=name; 13 } 14 15 public string Name 16 { 17 get 18 { 19 return _name; 20 } 21 set 22 { 23 _name = value; 24 } 25 } 26 override public string ToString() 27 { 28 return _name; 29 } 30 } 31}

Pilot.vb
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02Imports System 03 04Namespace Db4objects.Db4odoc.Refactoring 05 Public Class Pilot 06 Private _name As String 07 08 Public Sub New(ByVal name As String) 09 Me._name = name 10 End Sub 11 12 Public Property Name() As String 13 Get 14 Return _name 15 End Get 16 Set(ByVal Value As String) 17 _name = Value 18 End Set 19 End Property 20 Public Overrides Function ToString() As String 21 Return _name 22 End Function 23 End Class 24End Namespace

and change it to the new class PilotNew renaming field and changing package/namespace at the same time:

PilotNew.cs
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02using System; 03 04namespace Db4objects.Db4odoc.Refactoring 05{ 06 public class PilotNew 07 { 08 private string _identity; 09 private int _points; 10 11 public PilotNew(string name, int points) 12 { 13 _identity = name; 14 _points = points; 15 } 16 17 public string Identity 18 { 19 get 20 { 21 return _identity; 22 } 23 } 24 25 override public string ToString() 26 { 27 return string.Format("{0}/{1}",_identity,_points); 28 } 29 } 30}

PilotNew.vb
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02Imports System 03 04Namespace Db4objects.Db4odoc.Refactoring 05 Public Class PilotNew 06 Private _identity As String 07 Private _points As Integer 08 09 Public Sub New(ByVal name As String, ByVal points As Integer) 10 _identity = name 11 _points = points 12 End Sub 13 14 Public ReadOnly Property Identity() As String 15 Get 16 Return _identity 17 End Get 18 End Property 19 20 Public Overrides Function ToString() As String 21 Return String.Format("{0}/{1}", _identity, _points) 22 End Function 23 End Class 24End Namespace

First let's create a database and fill it with some values:

RefactoringExample.cs: SetObjects
01public static void SetObjects() 02 { 03 File.Delete(YapFileName); 04 IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 05 try 06 { 07 Pilot pilot = new Pilot("Rubens Barrichello"); 08 oc.Set(pilot); 09 pilot = new Pilot("Michael Schumacher"); 10 oc.Set(pilot); 11 } 12 finally 13 { 14 oc.Close(); 15 } 16 }

RefactoringExample.vb: SetObjects
01Public Shared Sub SetObjects() 02 File.Delete(YapFileName) 03 Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 04 Try 05 Dim pilot As Pilot = New Pilot("Rubens Barrichello") 06 oc.Set(pilot) 07 pilot = New Pilot("Michael Schumacher") 08 oc.Set(pilot) 09 Finally 10 oc.Close() 11 End Try 12 End Sub

RefactoringExample.cs: CheckDB
01public static void CheckDB() 02 { 03 IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 04 try 05 { 06 IObjectSet result = oc.Get(typeof(Pilot)); 07 for (int i=0; i< result.Size();i++) 08 { 09 Pilot pilot = (Pilot)result[i]; 10 System.Console.WriteLine("Pilot="+ pilot); 11 } 12 } 13 finally 14 { 15 oc.Close(); 16 } 17 }

RefactoringExample.vb: CheckDB
01Public Shared Sub CheckDB() 02 Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 03 Try 04 Dim result As IObjectSet = oc.Get(GetType(Pilot)) 05 Dim i As Integer 06 For i = 0 To result.Size() - 1 Step i + 1 07 Dim pilot As Pilot = CType(result(i), Pilot) 08 System.Console.WriteLine("Pilot=" + pilot.ToString()) 09 Next 10 Finally 11 oc.Close() 12 End Try 13 End Sub

We already have PilotNew class so we can go on with renaming:

RefactoringExample.cs: ChangeClass
1public static void ChangeClass() 2 { 3 Db4oFactory.Configure().ObjectClass(typeof(Pilot)).Rename("Db4objects.Db4odoc.Refactoring.PilotNew, db4o-reference-chapters"); 4 Db4oFactory.Configure().ObjectClass(typeof(PilotNew)).ObjectField("_name").Rename("_identity"); 5 IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 6 oc.Close(); 7 }

RefactoringExample.vb: ChangeClass
1Public Shared Sub ChangeClass() 2 Db4oFactory.Configure().ObjectClass(GetType(Pilot)).Rename("Db4objects.Db4odoc.Refactoring.PilotNew, Db4objects.Db4odoc") 3 Db4oFactory.Configure().ObjectClass(GetType(PilotNew)).ObjectField("_name").Rename("_identity") 4 Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 5 oc.Close() 6 End Sub

Now the data for the old Pilot class should be transferred to the new PilotNew class, and "name" field data should be stored in "identity" field.

To make our check more complicated let's add some data for our new class:

RefactoringExample.cs: SetNewObjects
01public static void SetNewObjects() 02 { 03 IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 04 try 05 { 06 PilotNew pilot = new PilotNew("Rubens Barrichello",99); 07 oc.Set(pilot); 08 pilot = new PilotNew("Michael Schumacher",100); 09 oc.Set(pilot); 10 } 11 finally 12 { 13 oc.Close(); 14 } 15 }

RefactoringExample.vb: SetNewObjects
01Public Shared Sub SetNewObjects() 02 Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 03 Try 04 Dim pilot As PilotNew = New PilotNew("Rubens Barrichello", 99) 05 oc.Set(pilot) 06 pilot = New PilotNew("Michael Schumacher", 100) 07 oc.Set(pilot) 08 Finally 09 oc.Close() 10 End Try 11 End Sub

We can check what is stored in the database now:

RefactoringExample.cs: RetrievePilotNew
01public static void RetrievePilotNew() 02 { 03 IObjectContainer oc = Db4oFactory.OpenFile(YapFileName); 04 try 05 { 06 IQuery q = oc.Query(); 07 q.Constrain(typeof(PilotNew)); 08 IObjectSet result = q.Execute(); 09 for (int i=0; i< result.Size();i++) 10 { 11 PilotNew pilot = (PilotNew)result[i]; 12 System.Console.WriteLine("Pilot="+ pilot); 13 } 14 } 15 finally 16 { 17 oc.Close(); 18 } 19 }

RefactoringExample.vb: RetrievePilotNew
01Public Shared Sub RetrievePilotNew() 02 Dim oc As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 03 Try 04 Dim q As IQuery = oc.Query() 05 q.Constrain(GetType(PilotNew)) 06 Dim result As IObjectSet = q.Execute() 07 Dim i As Integer 08 For i = 0 To result.Size() - 1 Step i + 1 09 Dim pilot As PilotNew = CType(result(i), PilotNew) 10 System.Console.WriteLine("Pilot=" + pilot.ToString()) 11 Next 12 Finally 13 oc.Close() 14 End Try 15 End Sub

There is one thing to remember. The rename feature is intended to rename a class from one name to the other. Internally this will rename the meta-information. If you will try to rename class to the name that is already stored in the database, the renaming will fail, because the name is reserved. In our example it will happen if setNewObjects method will be called before changeClass.