| # 10. SODA Evaluations In the SODA API chapter we already mentioned Evaluations as a means of providing user-defined custom constraints and as a means to run any arbitrary code in a SODA query. Let's have a closer look. ## 10.1. Evaluation API The evaluation API consists of two interfaces, Evaluation and Candidate . Evaluation implementations are implemented by the user and injected into a query. During a query, they will be called from db4o with a candidate instance in order to decide whether to include it into the current (sub-)result. The Evaluation interface contains a single method only:
`public void evaluate(Candidate candidate);`
This will be called by db4o to check whether the object encapsulated by this candidate should be included into the current candidate set. The Candidate interface provides three methods:
`public Object getObject(); public void include(boolean flag); public ObjectContainer objectContainer();`
An Evaluation implementation may call getObject() to retrieve the actual object instance to be evaluated, it may call include() to instruct db4o whether or not to include this object in the current candidate set, and finally it may access the current database directly by calling objectContainer(). ## 10.2. Example For a simple example, let's go back to our Pilot/Car implementation from the Collections chapter. Back then, we kept a history of SensorReadout instances in a List member inside the car. Now imagine that we wanted to retrieve all cars that have assembled an even number of history entries. A quite contrived and seemingly trivial example, however, it gets us into trouble: Collections are transparent to the query API, it just 'looks through' them at their respective members. So how can we get this done? Let's implement an Evaluation that expects the objects passed in to be instances of type Car and checks their history size.
`Imports com.db4o.query Namespace com.db4o.f1.chapter6 Public Class EvenHistoryEvaluation Implements Evaluation Public Sub Evaluate(ByVal candidate As Candidate) Implements Evaluation.Evaluate Dim car As chapter3.Car = DirectCast(candidate.GetObject(), chapter3.Car) candidate.Include(car.History.Count Mod 2 = 0) End Sub End Class End Namespace`
To test it, let's add two cars with history sizes of one, respectively two:
`[storeCars] Dim pilot1 As chapter3.Pilot = New chapter3.Pilot("Michael Schumacher", 100) Dim car1 As chapter3.Car = New chapter3.Car("Ferrari") car1.Pilot = pilot1 car1.Snapshot() db.[Set](car1) Dim pilot2 As chapter3.Pilot = New chapter3.Pilot("Rubens Barrichello", 99) Dim car2 As chapter3.Car = New chapter3.Car("BMW") car2.Pilot = pilot2 car2.Snapshot() car2.Snapshot() db.[Set](car2)`
and run our evaluation against them:
`[queryWithEvaluation] Dim query As Query = db.Query() query.Constrain(GetType(chapter3.Car)) query.Constrain(New EvenHistoryEvaluation()) Dim result As ObjectSet = query.Execute() Util.ListResult(result)`
OUTPUT: 1 BMW[Rubens Barrichello/99]/2

## 10.3. Drawbacks

While evaluations offer you another degree of freedom for assembling queries, they come at a certain cost: As you may already have noticed from the example, evaluations work on the fully instantiated objects, while 'normal' queries peek into the database file directly. So there's a certain performance penalty for the object instantiation, which is wasted if the object is not included into the candidate set.
Another restriction is that, while 'normal' queries can bypass encapsulation and access candidates' private members directly, evaluations are bound to use their external API, just as in the language itself.

## 10.4. Conclusion

With the introduction of evaluations we finally completed our query toolbox. Evaluations provide a simple way of assemble arbitrary custom query building blocks, however, they come at a price.

## 10.5. Full source

`Imports System.IO Imports com.db4o.query Imports com.db4o Namespace com.db4o.f1.chapter6 Public Class EvaluationExample Inherits Util Public Shared Sub Main(ByVal args As String()) File.Delete(Util.YapFileName) Dim db As Global.com.db4o.ObjectContainer = Db4oFactory.OpenFile(Util.YapFileName) Try StoreCars(db) QueryWithEvaluation(db) Finally db.Close() End Try End Sub Public Shared Sub StoreCars(ByVal db As ObjectContainer) Dim pilot1 As chapter3.Pilot = New chapter3.Pilot("Michael Schumacher", 100) Dim car1 As chapter3.Car = New chapter3.Car("Ferrari") car1.Pilot = pilot1 car1.Snapshot() db.[Set](car1) Dim pilot2 As chapter3.Pilot = New chapter3.Pilot("Rubens Barrichello", 99) Dim car2 As chapter3.Car = New chapter3.Car("BMW") car2.Pilot = pilot2 car2.Snapshot() car2.Snapshot() db.[Set](car2) End Sub Public Shared Sub QueryWithEvaluation(ByVal db As ObjectContainer) Dim query As Query = db.Query() query.Constrain(GetType(chapter3.Car)) query.Constrain(New EvenHistoryEvaluation()) Dim result As ObjectSet = query.Execute() Util.ListResult(result) End Sub End Class End Namespace`

--
generated by Doctor courtesy of db4objects Inc.