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.
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02
03
using Db4objects.Db4o; 04
using Db4objects.Db4o.Config; 05
06
namespace 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
}
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02
03
Imports Db4objects.Db4o 04
Imports Db4objects.Db4o.Config 05
06
Namespace 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 50
End Namespace
Let's clean our database and store 2 cars:
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
}
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:
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
}
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:
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02
03
namespace 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
}
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02
03
Imports Db4objects.Db4o.Query 04
05
Namespace 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 13
End Namespace
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
}
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.
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
}
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:
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02
using Db4objects.Db4o.Query; 03
04
namespace 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
}
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02
03
Imports Db4objects.Db4o.Query 04
05
Namespace 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 14
End Namespace
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
}
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.