<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <link rel="stylesheet" type="text/css" href="docs.css"> <!--[if gte IE 5]> <link href="docs_ie.css" rel="stylesheet" type="text/css"> <![endif]--> </head> <body><div id="pagecontainer"><table><tr><td width="5"> </td><td><a name="Evaluations"></a><br> <a name="outline219"></a><br><h1>13. SODA Evaluations</h1><br> In the <a href="Query.html#SODAQueryAPI">SODA API chapter</a> we already mentioned <em>Evaluations</em> 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.<br> <br> <ul> <a name="outline220"></a><br><h2>13.1. Evaluation API</h2><br> The evaluation API consists of two interfaces, IEvaluation and ICandidate . 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.<br> <br> <br> The IEvaluation interface contains a single method only:<br> <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>public void Evaluate(ICandidate candidate);</code></td></tr></table> <br> <br> This will be called by db4o to check whether the object encapsulated by this candidate should be included into the current candidate set.<br> <br> <br> The ICandidate interface provides three methods:<br> <br> <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>public object GetObject();<br> public void Include(bool flag);<br> public IObjectContainer ObjectContainer();<br> </code></td></tr></table> <br> <br> 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() .<br> <br> <br> <a name="outline221"></a><br><h2>13.2. Example</h2><br> For a simple example, let's go back to our Pilot/Car implementation from the <a href="Collections.html#Collections">Collections chapter</a>. 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.<br> <br> <br> 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.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using Db4objects.Db4o.Query;<br> using Db4odoc.Tutorial.F1.Chapter4;<br> namespace Db4odoc.Tutorial.F1.Chapter7<br> { <br> public class EvenHistoryEvaluation : IEvaluation<br> {<br> public void Evaluate(ICandidate candidate)<br> {<br> Car car=(Car)candidate.GetObject();<br> candidate.Include(car.History.Count % 2 == 0);<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> To test it, let's add two cars with history sizes of one, respectively two:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// storeCars<br> Pilot pilot1 = new Pilot("Michael Schumacher", 100);<br> Car car1 = new Car("Ferrari");<br> car1.Pilot = pilot1;<br> car1.Snapshot();<br> db.Store(car1);<br> Pilot pilot2 = new Pilot("Rubens Barrichello", 99);<br> Car car2 = new Car("BMW");<br> car2.Pilot = pilot2;<br> car2.Snapshot();<br> car2.Snapshot();<br> db.Store(car2);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter7.EvaluationExample", "storeCars")' /></td></tr></table> <br> <br> and run our evaluation against them:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// queryWithEvaluation<br> IQuery query = db.Query();<br> query.Constrain(typeof (Car));<br> query.Constrain(new EvenHistoryEvaluation());<br> IObjectSet result = query.Execute();<br> Util.ListResult(result);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter7.EvaluationExample", "queryWithEvaluation")' /></td></tr></table> <br> <br> <a name="outline222"></a><br><h2>13.3. Drawbacks</h2><br> 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.<br> <br> <br> 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.<br> <br> <br> <br> <a name="outline223"></a><br><h2>13.4. Conclusion</h2><br> 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.<br> <br> <a name="outline224"></a><br><h2>13.5. Full source</h2><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using System.IO;<br> using Db4objects.Db4o;<br> using Db4objects.Db4o.Query;<br> using Db4odoc.Tutorial.F1.Chapter4;<br> namespace Db4odoc.Tutorial.F1.Chapter7<br> {<br> public class EvaluationExample : Util<br> {<br> readonly static string YapFileName = Path.Combine(<br> Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),<br> "formula1.yap"); <br> public static void Main(string[] args)<br> { <br> File.Delete(YapFileName);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))<br> {<br> StoreCars(db);<br> QueryWithEvaluation(db);<br> }<br> }<br> public static void StoreCars(IObjectContainer db)<br> {<br> Pilot pilot1 = new Pilot("Michael Schumacher", 100);<br> Car car1 = new Car("Ferrari");<br> car1.Pilot = pilot1;<br> car1.Snapshot();<br> db.Store(car1);<br> Pilot pilot2 = new Pilot("Rubens Barrichello", 99);<br> Car car2 = new Car("BMW");<br> car2.Pilot = pilot2;<br> car2.Snapshot();<br> car2.Snapshot();<br> db.Store(car2);<br> }<br> public static void QueryWithEvaluation(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof (Car));<br> query.Constrain(new EvenHistoryEvaluation());<br> IObjectSet result = query.Execute();<br> Util.ListResult(result);<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br><br><div id="footer"><p align="center">Do you have any questions, suggestions or feedback? Ask your questions in the <a href="http://developer.db4o.com/Forums.aspx" target=_top>db4o forums</a>. Join the <a href="http://developer.db4o.com" target=_top>db4o community</a> for addional resources and news.<br><br><a href="http://www.db4o.com/" target=_top><small>www.db4o.com</small></a></p>.</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></td></tr></table></div></body></html>