DescendIntoTranslator

Translator API provides a special way of storing and retrieving objects. In fact the actual class is not stored in the database. Instead the information from that class is stored in a primitive object (object array) and the class is recreated during instantiation or activation.

Let's look how queries handle translated classes. Diagnostics system will help us to see, what is going on.

In our example class Car is configured to be saved and retrieved with CarTranslator class. CarTranslator saves only car model information appending it with the production date.

CarTranslator.cs
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02 03using Db4objects.Db4o; 04using Db4objects.Db4o.Config; 05 06namespace Db4objects.Db4odoc.Diagnostics 07{ 08 09 public class CarTranslator: IObjectConstructor 10 { 11 public object OnStore(IObjectContainer container, object applicationObject) 12 { 13 Car car =(Car)applicationObject; 14 15 string fullModel; 16 if (HasYear(car.Model)) 17 { 18 fullModel = car.Model; 19 } 20 else 21 { 22 fullModel = car.Model + GetYear(car.Model); 23 } 24 return fullModel; 25 } 26 27 private string GetYear(string carModel) 28 { 29 if (carModel.Equals("BMW")) 30 { 31 return " 2002"; 32 } 33 else 34 { 35 return " 1999"; 36 } 37 } 38 39 private bool HasYear(string carModel) 40 { 41 return false; 42 } 43 44 public object OnInstantiate(IObjectContainer container, object storedObject) 45 { 46 string model=(string)storedObject; 47 return new Car(model); 48 } 49 50 public void OnActivate(IObjectContainer container, 51 object applicationObject, object storedObject) 52 { 53 } 54 55 IObjectTranslator Members 64 } 65}

CarTranslator.vb
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02 03Imports Db4objects.Db4o 04Imports Db4objects.Db4o.Config 05 06Namespace Db4objects.Db4odoc.Diagnostics 07 08 Public Class CarTranslator 09 Implements IObjectConstructor 10 11 Public Function OnStore(ByVal container As IObjectContainer, ByVal applicationObject As Object) As Object Implements IObjectConstructor.OnStore 12 Dim car As Car = CType(applicationObject, Car) 13 14 Dim fullModel As String 15 If HasYear(car.Model) Then 16 fullModel = car.Model 17 Else 18 fullModel = car.Model + GetYear(car.Model) 19 End If 20 Return fullModel 21 22 End Function 23 24 25 Private Function GetYear(ByVal carModel As String) As String 26 If carModel.Equals("BMW") Then 27 Return " 2002" 28 Else 29 Return " 1999" 30 End If 31 End Function 32 33 Private Function HasYear(ByVal carModel As String) As Boolean 34 Return False 35 End Function 36 37 Public Function OnInstantiate(ByVal container As IObjectContainer, ByVal storedObject As Object) As Object Implements IObjectConstructor.OnInstantiate 38 Dim model As String = DirectCast(storedObject, String) 39 Return New Car(model) 40 End Function 41 42 Public Sub OnActivate(ByVal container As IObjectContainer, ByVal applicationObject As Object, ByVal storedObject As Object) Implements IObjectConstructor.OnActivate 43 End Sub 44 45 Public Function StoredClass() As System.Type Implements IObjectConstructor.StoredClass 46 Return GetType(String) 47 End Function 48 49 End Class 50End Namespace

Let's clean our database and store 2 cars:

DiagnosticExample.cs: StoreTranslatedCars
01public static void StoreTranslatedCars() { 02 Db4oFactory.Configure().ExceptionsOnNotStorable(true); 03 Db4oFactory.Configure().ObjectClass(typeof(Car)).Translate(new CarTranslator()); 04 Db4oFactory.Configure().ObjectClass(typeof(Car)).CallConstructor(true); 05 File.Delete(YapFileName); 06 IObjectContainer db = Db4oFactory.OpenFile(YapFileName); 07 try { 08 Car car1 = new Car("BMW"); 09 System.Diagnostics.Trace.WriteLine("ORIGINAL: " + car1); 10 db.Set(car1); 11 Car car2 = new Car("Ferrari"); 12 System.Diagnostics.Trace.WriteLine("ORIGINAL: " + car2); 13 db.Set(car2); 14 } catch (Exception exc) { 15 System.Diagnostics.Trace.WriteLine(exc.Message); 16 return; 17 } finally { 18 db.Close(); 19 } 20 }

DiagnosticExample.vb: StoreTranslatedCars
01Public Shared Sub StoreTranslatedCars() 02 Db4oFactory.Configure().ExceptionsOnNotStorable(True) 03 Db4oFactory.Configure().ObjectClass(GetType(Car)).Translate(New CarTranslator()) 04 Db4oFactory.Configure().ObjectClass(GetType(Car)).CallConstructor(True) 05 File.Delete(YapFileName) 06 Dim db As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 07 Try 08 Dim car1 As Car = New Car("BMW") 09 System.Diagnostics.Trace.WriteLine("ORIGINAL: " + car1.ToString()) 10 db.Set(car1) 11 Dim car2 As Car = New Car("Ferrari") 12 System.Diagnostics.Trace.WriteLine("ORIGINAL: " + car2.ToString()) 13 db.Set(car2) 14 Catch exc As Exception 15 System.Diagnostics.Trace.WriteLine(exc.Message) 16 Return 17 Finally 18 db.Close() 19 End Try 20 End Sub

We can check the contents of our database with the following method:

DiagnosticExample.cs: RetrieveTranslatedCars
01public static void RetrieveTranslatedCars() { 02 Db4oFactory.Configure().Diagnostic().RemoveAllListeners(); 03 Db4oFactory.Configure().Diagnostic().AddListener(new TranslatorDiagListener()); 04 Db4oFactory.Configure().ExceptionsOnNotStorable(true); 05 Db4oFactory.Configure().ObjectClass(typeof(Car)).Translate(new CarTranslator()); 06 Db4oFactory.Configure().ObjectClass(typeof(Car)).CallConstructor(true); 07 IObjectContainer db = Db4oFactory.OpenFile(YapFileName); 08 try { 09 IQuery query = db.Query(); 10 query.Constrain(typeof(Car)); 11 IObjectSet result = query.Execute(); 12 ListResult(result); 13 } finally { 14 db.Close(); 15 } 16 }

DiagnosticExample.vb: RetrieveTranslatedCars
01Public Shared Sub RetrieveTranslatedCars() 02 Db4oFactory.Configure().Diagnostic().RemoveAllListeners() 03 Db4oFactory.Configure().Diagnostic().AddListener(New TranslatorDiagListener()) 04 Db4oFactory.Configure().ExceptionsOnNotStorable(True) 05 Db4oFactory.Configure().ObjectClass(GetType(Car)).Translate(New CarTranslator()) 06 Db4oFactory.Configure().ObjectClass(GetType(Car)).CallConstructor(True) 07 Dim db As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 08 Try 09 Dim query As IQuery = db.Query() 10 query.Constrain(GetType(Car)) 11 Dim result As IObjectSet = query.Execute() 12 ListResult(result) 13 Finally 14 db.Close() 15 End Try 16 End Sub

TranslatorDiagListener is implemented to help us filter only those diagnostic messages, that concern translated classes (filtering diagnostics messages is explained in Diagnostic Messages Filter chapter).

We did not get any diagnostic messages here and the result shows the stored cars with extended model values.

To test Native Queries we will use the predicate, which retrieves only cars, produced in year 2002:

NewCarModel.cs
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02 03namespace Db4objects.Db4odoc.Diagnostics 04{ 05 06 public class NewCarModel : Db4objects.Db4o.Query.Predicate 07 { 08 public bool Match(Car car) 09 { 10 return car.Model.EndsWith("2002"); 11 } 12 } 13}

NewCarModel.vb
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02 03Imports Db4objects.Db4o.Query 04 05Namespace Db4objects.Db4odoc.Diagnostics 06 07 Public Class NewCarModel 08 Inherits Predicate 09 Public Function Match(ByVal car As evaluations.Car) As Boolean 10 Return car.Model.EndsWith("2002") 11 End Function 12 End Class 13End Namespace

DiagnosticExample.cs: RetrieveTranslatedCarsNQ
01public static void RetrieveTranslatedCarsNQ() { 02 Db4oFactory.Configure().Diagnostic().RemoveAllListeners(); 03 Db4oFactory.Configure().Diagnostic().AddListener(new TranslatorDiagListener()); 04 Db4oFactory.Configure().ExceptionsOnNotStorable(true); 05 Db4oFactory.Configure().ObjectClass(typeof(Car)).Translate(new CarTranslator()); 06 Db4oFactory.Configure().ObjectClass(typeof(Car)).CallConstructor(true); 07 IObjectContainer db = Db4oFactory.OpenFile(YapFileName); 08 try { 09 IObjectSet result = db.Query(new NewCarModel()); 10 ListResult(result); 11 } finally { 12 db.Close(); 13 } 14 }

DiagnosticExample.vb: RetrieveTranslatedCarsNQ
01Public Shared Sub RetrieveTranslatedCarsNQ() 02 Db4oFactory.Configure().Diagnostic().RemoveAllListeners() 03 Db4oFactory.Configure().Diagnostic().AddListener(New TranslatorDiagListener()) 04 Db4oFactory.Configure().ExceptionsOnNotStorable(True) 05 Db4oFactory.Configure().ObjectClass(GetType(Car)).Translate(New CarTranslator()) 06 Db4oFactory.Configure().ObjectClass(GetType(Car)).CallConstructor(True) 07 Dim db As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 08 Try 09 Dim result As IObjectSet = db.Query(New NewCarModel()) 10 ListResult(result) 11 Finally 12 db.Close() 13 End Try 14 End Sub

A diagnostic message should appear pointing out, that the query is not correct in our case. Let's try  to correct it using unoptimized NQ and evaluations.

DiagnosticExample.cs: RetrieveTranslatedCarsNQUnopt
01public static void RetrieveTranslatedCarsNQUnopt() { 02 Db4oFactory.Configure().OptimizeNativeQueries(false); 03 Db4oFactory.Configure().Diagnostic().RemoveAllListeners(); 04 Db4oFactory.Configure().Diagnostic().AddListener(new TranslatorDiagListener()); 05 Db4oFactory.Configure().ExceptionsOnNotStorable(true); 06 Db4oFactory.Configure().ObjectClass(typeof(Car)).Translate(new CarTranslator()); 07 Db4oFactory.Configure().ObjectClass(typeof(Car)).CallConstructor(true); 08 IObjectContainer db = Db4oFactory.OpenFile(YapFileName); 09 try { 10 IObjectSet result = db.Query(new NewCarModel()); 11 ListResult(result); 12 } finally { 13 Db4oFactory.Configure().OptimizeNativeQueries(true); 14 db.Close(); 15 } 16 }

DiagnosticExample.vb: RetrieveTranslatedCarsNQUnopt
01Public Shared Sub RetrieveTranslatedCarsNQUnopt() 02 Db4oFactory.Configure().OptimizeNativeQueries(False) 03 Db4oFactory.Configure().Diagnostic().RemoveAllListeners() 04 Db4oFactory.Configure().Diagnostic().AddListener(New TranslatorDiagListener()) 05 Db4oFactory.Configure().ExceptionsOnNotStorable(True) 06 Db4oFactory.Configure().ObjectClass(GetType(Car)).Translate(New CarTranslator()) 07 Db4oFactory.Configure().ObjectClass(GetType(Car)).CallConstructor(True) 08 Dim db As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 09 Try 10 Dim result As IObjectSet = db.Query(New NewCarModel()) 11 ListResult(result) 12 Finally 13 Db4oFactory.Configure().OptimizeNativeQueries(True) 14 db.Close() 15 End Try 16 End Sub

We will use simple evaluation to check our cars:

CarEvaluation.cs
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02using Db4objects.Db4o.Query; 03 04namespace Db4objects.Db4odoc.Diagnostics 05{ 06 07 public class CarEvaluation:IEvaluation 08 { 09 public void Evaluate(ICandidate candidate) 10 { 11 Car car=(Car)candidate.GetObject(); 12 candidate.Include(car.Model.EndsWith("2002")); 13 } 14 } 15}

CarEvaluation.vb
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02 03Imports Db4objects.Db4o.Query 04 05Namespace Db4objects.Db4odoc.Diagnostics 06 Public Class CarEvaluation 07 Implements IEvaluation 08 Public Sub Evaluate(ByVal candidate As ICandidate) Implements IEvaluation.Evaluate 09 Dim car As Car = CType(candidate.GetObject(), Car) 10 candidate.Include(car.Model.EndsWith("2002")) 11 End Sub 12 13 End Class 14End Namespace

DiagnosticExample.cs: RetrieveTranslatedCarsSODAEv
01public static void RetrieveTranslatedCarsSODAEv() { 02 Db4oFactory.Configure().Diagnostic().RemoveAllListeners(); 03 Db4oFactory.Configure().Diagnostic().AddListener(new TranslatorDiagListener()); 04 Db4oFactory.Configure().ExceptionsOnNotStorable(true); 05 Db4oFactory.Configure().ObjectClass(typeof(Car)).Translate(new CarTranslator()); 06 Db4oFactory.Configure().ObjectClass(typeof(Car)).CallConstructor(true); 07 IObjectContainer db = Db4oFactory.OpenFile(YapFileName); 08 try { 09 IQuery query = db.Query(); 10 query.Constrain(typeof(Car)); 11 query.Constrain(new CarEvaluation()); 12 IObjectSet result = query.Execute(); 13 ListResult(result); 14 } finally { 15 db.Close(); 16 } 17 }

DiagnosticExample.vb: RetrieveTranslatedCarsSODAEv
01Public Shared Sub RetrieveTranslatedCarsSODAEv() 02 Db4oFactory.Configure().Diagnostic().RemoveAllListeners() 03 Db4oFactory.Configure().Diagnostic().AddListener(New TranslatorDiagListener()) 04 Db4oFactory.Configure().ExceptionsOnNotStorable(True) 05 Db4oFactory.Configure().ObjectClass(GetType(Car)).Translate(New CarTranslator()) 06 Db4oFactory.Configure().ObjectClass(GetType(Car)).CallConstructor(True) 07 Dim db As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 08 Try 09 Dim query As IQuery = db.Query() 10 query.Constrain(GetType(Car)) 11 query.Constrain(New CarEvaluation()) 12 Dim result As IObjectSet = query.Execute() 13 ListResult(result) 14 Finally 15 db.Close() 16 End Try 17 End Sub

In both cases we the results are correct. Native Query optimization cannot be used with the translated classes, because the actual values of the translated fields are only known after instantiation and activation. That also means that translated classes can have a considerable impact on database performance and should be used with care.