<!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="Query"></a><br> <a name="outline142"></a><br><h1>4. Querying</h1><br> db4o supplies three querying systems, Query-By-Example (QBE) Native Queries (NQ), and the SODA API. In the previous chapter, you were briefly introduced to <em>Query By Example</em>(QBE).<br> <br> Query-By-Example (QBE) is appropriate as a quick start for users who are still acclimating to storing and retrieving objects with db4o.<br> <br> <br> LINQ is the recommended db4o querying interface for .NET platforms. <br> <br> SODA is the underlying internal API. It is provided for backward compatibility and it can be useful for dynamic generation of queries, where LINQ and NQ are too strongly typed.<br> <br> <a name="QBE"></a><br> <ul> <a name="outline143"></a><br><h2>4.1. Query by Example (QBE)</h2><br> When using <em>Query By Example</em> (QBE) you provide db4o with a template object. db4o will return all of the objects which match all non-default field values. This is done via reflecting all of the fields and building a query expression where all non-default-value fields are combined with AND expressions. Here's an example from the previous chapter:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrievePilotByName<br> Pilot proto = new Pilot("Michael Schumacher", 0);<br> IObjectSet result = db.QueryByExample(proto);<br> ListResult(result);</code></td></tr></table> <br> <br> Querying this way has some obvious limitations:<br> - db4o must reflect all members of your example object.<br> - You cannot perform advanced query expressions. (AND, OR, NOT, etc.)<br> - You cannot constrain on values like 0 (integers), "" (empty strings), or nulls (reference types) because they would be interpreted as unconstrained.<br> - You need to be able to create objects without initialized fields. That means you can not initialize fields where they are declared. You can not enforce contracts that objects of a class are only allowed in a well-defined initialized state.<br> - You need a constructor to create objects without initialized fields.<br> <br> To get around all of these constraints, db4o provides the Native Query (NQ) system.<br> <br> <br> <a name="NativeQueries"></a><br> <a name="outline144"></a><br><h2>4.2. Native Queries</h2><br> Wouldn't it be nice to pose queries in the programming language that you are using? Wouldn't it be nice if all your query code was 100% typesafe, 100% compile-time checked and 100% refactorable? Wouldn't it be nice if the full power of object-orientation could be used by calling methods from within queries? Enter Native Queries. <br> <br> Native queries are the main db4o query interface and they are the recommended way to query databases from your application. Because native queries simply use the semantics of your programming language, they are perfectly standardized and a safe choice for the future.<br> <br> Native Queries are available for all platforms supported by db4o.<br> <br> <ul> <a name="outline145"></a><br><h2>4.2.1. Concept</h2>The concept of native queries is taken from the following two papers:<br> <br> - <a href="http://www.cs.utexas.edu/users/wcook/papers/NativeQueries/NativeQueries8-23-05.pdf" target="_blank">Cook/Rosenberger, Native Queries for Persistent Objects, A Design White Paper</a><br> - <a href="http://www.cs.utexas.edu/users/wcook/papers/SafeQuery05/SafeQueryFinal.pdf" target="_blank">Cook/Rai, Safe Query Objects: Statically Typed Objects as Remotely Executable Queries</a><br> <br> <a name="outline146"></a><br><h2>4.2.2. Principle</h2>Native Queries provide the ability to run one or more lines of code against all instances of a class. Native query expressions should return true to mark specific instances as part of the result set. db4o will attempt to optimize native query expressions and run them against indexes and without instantiating actual objects, where this is possible.<br> <br> <a name="outline147"></a><br><h2>4.2.3. Simple Example</h2>Let's look at how a simple native query will look like in some of the programming languages and dialects that db4o supports:<br> <br> <b>C# .NET (using generics)</b><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>IList <Pilot> pilots = db.Query <Pilot> (delegate(Pilot pilot) {<br> return pilot.Points == 100;<br> });</code></td></tr></table> <br> <br> <b>Java JDK 5</b><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>List <Pilot> pilots = db.query(new Predicate<Pilot>() {<br> public boolean match(Pilot pilot) {<br> return pilot.getPoints() == 100;<br> }<br> });</code></td></tr></table> <br> <br> <b>Java JDK 1.2 to 1.4</b><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>List pilots = db.query(new Predicate() {<br> public boolean match(Pilot pilot) {<br> return pilot.getPoints() == 100;<br> }<br> });</code></td></tr></table> <br> <br> <b>Java JDK 1.1</b><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>ObjectSet pilots = db.query(new PilotHundredPoints());<br> <br> public static class PilotHundredPoints extends Predicate {<br> public boolean match(Pilot pilot) {<br> return pilot.getPoints() == 100;<br> }<br> }</code></td></tr></table> <br> <br> <b>C# .NET (not using generics)</b><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>IList pilots = db.Query(new PilotHundredPoints());<br> <br> public class PilotHundredPoints : Predicate {<br> public boolean Match(Pilot pilot) {<br> return pilot.Points == 100;<br> }<br> }</code></td></tr></table> <br> <br> <b>VB .NET (not using generics)</b><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>Dim pilots As IList = db.Query(new PilotHundredPoints())<br> <br> Public Class PilotHundredPoints <br> Inherits Predicate<br> Public Function Match (pilot As Pilot) as Boolean<br> If pilot.Points = 100 Then <br> Return True <br> Else <br> Return False<br> End Function<br> End Class</code></td></tr></table> <br> <br> A side note on the above syntax:<br> For all dialects without support for generics, Native Queries work by convention. A class that extends the com.db4o.Predicate class is expected to have a boolean #Match() method with one parameter to describe the class extent:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>bool Match(Pilot candidate);</code></td></tr></table> <br> <br> When using native queries, don't forget that modern integrated development environments (IDEs) can do all the typing work around the native query expression for you, if you use templates and auto-completion.<br> <br> The following example shows how to create an autocompletion code snippet in Visual Studio 2005.<br> Create a "nq.snippet" file in any text editor.<br> Paste the following code:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code> <?xml version="1.0" encoding="utf-8" ?><br> <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"><br> <CodeSnippet Format="1.0.0"><br> <Header><br> <Title>NQ</Title><br> <Shortcut>NQ</Shortcut><br> <Description>Code snippet for Native Query</Description><br> <Author>db4objects Inc.</Author><br> <SnippetTypes><br> <SnippetType>Expansion</SnippetType><br> </SnippetTypes><br> </Header><br> <Snippet><br> <Declarations><br> <Literal><br> <ID>type</ID><br> <ToolTip>Type</ToolTip><br> <Default>MyType</Default><br> </Literal><br> <Literal><br> <ID>var</ID><br> <ToolTip>variable</ToolTip><br> <Default>myType</Default><br> </Literal><br> <Literal><br> <ID>expression</ID><br> <ToolTip>Boolean expression</ToolTip><br> <Default>return true;</Default><br> </Literal><br> </Declarations><br> <Code Language="csharp"><![CDATA[ IList<$type$> list = db.Query<$type$>(delegate($type$ $var$)<br> {<br> $expression$<br> });]]><br> </Code><br> </Snippet><br> </CodeSnippet><br> </CodeSnippets> </code></td></tr></table> <br> <br> Save the file.<br> In the Visual Studio 2005 open Tools/Code SnippetsManager<br> Select language "Visual c#" if not yet selected. Press "Import..." button and select the newly created file. Select "Visual c#" as the location and press "Finish" button. <br> Now you can use the snippet by selecting it from "Edit/InstelliSense/Insert Snippet..." menu.<br> <br> <br> <a name="outline148"></a><br><h2>4.2.4. Advanced Example</h2>For complex queries, the native syntax is very precise and quick to write. Let's compare to a SODA query that finds all pilots with a given name or a score within a given range:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// storePilots<br> db.Store(new Pilot("Michael Schumacher", 100));<br> db.Store(new Pilot("Rubens Barrichello", 99));</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.chapter1.NQExample", "storePilots")' /></td></tr></table> <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveComplexSODA<br> IQuery query=db.Query();<br> query.Constrain(typeof(Pilot));<br> IQuery pointQuery=query.Descend("_points");<br> query.Descend("_name").Constrain("Rubens Barrichello")<br> .Or(pointQuery.Constrain(99).Greater()<br> .And(pointQuery.Constrain(199).Smaller()));<br> IObjectSet result=query.Execute();<br> 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.chapter1.NQExample", "retrieveComplexSODA")' /></td></tr></table> <br> <br> Here is how the same query will look like with native query syntax, fully accessible to autocompletion, refactoring and other IDE features, fully checked at compile time:<br> <br> <b>C# .NET 2.0</b><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>IList <Pilot> result = db.Query<Pilot> (delegate(Pilot pilot) {<br> return pilot.Points > 99<br> && pilot.Points < 199<br> || pilot.Name == "Rubens Barrichello";<br> });</code></td></tr></table> <br> <br> <b>Java JDK 5</b><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>List <Pilot> result = db.query(new Predicate<Pilot>() {<br> public boolean match(Pilot pilot) {<br> return pilot.getPoints() > 99<br> && pilot.getPoints() < 199<br> || pilot.getName().equals("Rubens Barrichello");<br> }<br> });</code></td></tr></table> <br> <br> <a name="outline149"></a><br><h2>4.2.5. Arbitrary Code</h2>Basically that's all there is to know about native queries to be able to use them efficiently. In principle you can run arbitrary code as native queries, you just have to be very careful with side effects - especially those that might affect persistent objects.<br> <br> Let's run an example that involves some more of the language features available.<br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using Db4objects.Db4o.Query;<br> namespace Db4odoc.Tutorial.F1.Chapter1<br> {<br> public class ArbitraryQuery : Predicate<br> {<br> private int[] _points;<br> <br> public ArbitraryQuery(int[] points)<br> {<br> _points=points;<br> }<br> <br> public bool Match(Pilot pilot)<br> {<br> foreach (int points in _points)<br> {<br> if (pilot.Points == points)<br> {<br> return true;<br> }<br> }<br> return pilot.Name.StartsWith("Rubens");<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> <br> <a name="outline150"></a><br><h2>4.2.6. Native Query Performance</h2>One drawback of native queries has to be pointed out: Under the hood db4o tries to analyze native queries to convert them to SODA. This is not possible for all queries. For some queries it is very difficult to analyze the flowgraph. In this case db4o will have to instantiate some of the persistent objects to actually run the native query code. db4o will try to analyze parts of native query expressions to keep object instantiation to the minimum.<br> <br> The development of the native query optimization processor will be an ongoing process in a close dialog with the db4o community. Feel free to contribute your results and your needs by providing feedback to our <a href="http://forums.db4o.com/" target="_blank">db4o forums</a>(Forums are accessible through <a href="http://developer.db4o.com/user/CreateUser.aspx?ReturnUrl=/default.aspx" target="_blank">free db4o membership </a> ).<br> <br> <br> With the current implementation, all above examples will run optimized, except for the "Arbitrary Code" example - we are working on it.<br> <br> <a name="outline151"></a><br><h2>4.2.7. 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;<br> namespace Db4odoc.Tutorial.F1.Chapter1<br> {<br> public class NQExample : Util<br> {<br> readonly static string YapFileName = Path.Combine(<br> Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),<br> "formula1.yap"); <br> <br> public static void Main(string[] args)<br> {<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))<br> {<br> StorePilots(db);<br> RetrieveComplexSODA(db);<br> RetrieveComplexNQ(db);<br> RetrieveArbitraryCodeNQ(db);<br> ClearDatabase(db);<br> }<br> }<br> <br> public static void StorePilots(IObjectContainer db)<br> {<br> db.Store(new Pilot("Michael Schumacher", 100));<br> db.Store(new Pilot("Rubens Barrichello", 99));<br> }<br> <br> public static void RetrieveComplexSODA(IObjectContainer db)<br> {<br> IQuery query=db.Query();<br> query.Constrain(typeof(Pilot));<br> IQuery pointQuery=query.Descend("_points");<br> query.Descend("_name").Constrain("Rubens Barrichello")<br> .Or(pointQuery.Constrain(99).Greater()<br> .And(pointQuery.Constrain(199).Smaller()));<br> IObjectSet result=query.Execute();<br> ListResult(result);<br> }<br> public static void RetrieveComplexNQ(IObjectContainer db)<br> {<br> IObjectSet result = db.Query(new ComplexQuery());<br> ListResult(result);<br> }<br> public static void RetrieveArbitraryCodeNQ(IObjectContainer db)<br> {<br> IObjectSet result = db.Query(new ArbitraryQuery(new int[]{1,100}));<br> ListResult(result);<br> }<br> <br> public static void ClearDatabase(IObjectContainer db)<br> {<br> IObjectSet result = db.QueryByExample(typeof(Pilot));<br> while (result.HasNext())<br> {<br> db.Delete(result.Next());<br> }<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using Db4objects.Db4o.Query;<br> namespace Db4odoc.Tutorial.F1.Chapter1<br> {<br> public class ComplexQuery : Predicate<br> {<br> public bool Match(Pilot pilot)<br> {<br> return pilot.Points > 99<br> && pilot.Points < 199<br> || pilot.Name=="Rubens Barrichello";<br> }<br> }<br> }<br> </code></td></tr></table> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using Db4objects.Db4o.Query;<br> namespace Db4odoc.Tutorial.F1.Chapter1<br> {<br> public class ArbitraryQuery : Predicate<br> {<br> private int[] _points;<br> <br> public ArbitraryQuery(int[] points)<br> {<br> _points=points;<br> }<br> <br> public bool Match(Pilot pilot)<br> {<br> foreach (int points in _points)<br> {<br> if (pilot.Points == points)<br> {<br> return true;<br> }<br> }<br> return pilot.Name.StartsWith("Rubens");<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> <br> <a name="LINQ"></a><br> </ul> <a name="outline152"></a><br><h2>4.3. LINQ</h2><br> db4o querying syntax has got even easier with the introduction of .NET LINQ queries. LINQ allows you to write compile checked db4o queries, which can be refactored automatically when a field name changes and which are supported by code auto-completion tools.<br> In order to use LINQ you will need to add reference to Db4objects.Db4o.Linq.dll and usage to your program class:<br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System.Linq;<br> using Db4objects.Db4o.Linq;</code></td></tr></table> <br> <br> If you are already familiar with LINQ syntax, you can just start writing LINQ to query db4o. Otherwise you may want to familiarise yourself with LINQ resources on <a href="http://msdn2.microsoft.com/en-us/library/bb397926.aspx" target="_blank">http://msdn2.microsoft.com/en-us/library/bb397926.aspx</a> MSDN.<br> <br> Note that LINQ requires at least .NET 3.5.<br> <br> <ul> <a name="outline153"></a><br><h2>4.3.1. Linq Examples</h2>Let's prepare some objects in our database to query against:<br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// storeObjects<br> db.Store(new Car("Ferrari", (new Pilot("Michael Schumacher", 100))));<br> db.Store(new Car("BMW", (new Pilot("Rubens Barrichello", 99))));</code></td></tr></table> <br> <br> The simplest LINQ query will look like this:<br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrievePilot<br> IEnumerable<Pilot> result = from Pilot p in db<br> where p.Name.StartsWith("Michael")<br> select p;<br> ListResult(result);</code></td></tr></table> <br> You can see that we are using db4o object container as a datasource, the rest of the syntax is generic to all LINQ queries.<br> <br> Now let's try a bit more complex selection:<br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrievePilotByCar<br> IEnumerable<Pilot> result = from Car c in db<br> where c.Model.StartsWith("F")<br> && (c.Pilot.Points > 99 && c.Pilot.Points <150)<br> select c.Pilot;<br> ListResult(result);</code></td></tr></table> <br> So we can constrain on one object and retrieve a list of others. You can even create completely new objects based on the retrieved information using <em>select new MyObject(field1, field2...)</em>. Try to experiment with different LINQ queries against db4o database.<br> <br> <a name="outline154"></a><br><h2>4.3.2. Performance</h2>db4o query processor is based on SODA queries, therefore LINQ query is analysed and converted to SODA syntax in the runtime. However, in some cases this conversion is not possible. This can happen when query is constrained against aggregates or projections of a field value and in other cases when SODA equivalent does not exists. For example:<br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrievePilotUnoptimized<br> IEnumerable<Pilot> result = from Pilot p in db<br> where (p.Points - 81) == p.Name.Length<br> select p;<br> ListResult(result);</code></td></tr></table> <br> The query still works, but it requires instantiation of all candidate objects, which is much less performant than SODA query. <br> <br> <a name="outline155"></a><br><h2>4.3.3. LINQ for Compact Framework</h2>Compact Framework version 3.5 contains LINQ implementation for querying objects, however it does not contain the namespace System.Linq.Expressions, which is used by all optimized LINQ providers. Luckily there is a solution to this problem. Mono implementation of System.Core can be used to support optimized LINQ providers and expression interpreter contributed by <a href="http://www.mainsoft.com/" target="_blank">Mainsoft</a> to Mono's System.Core can be used to support full LINQ expression trees.<br> <br> These assemblies were used by db4o team to compile a new assembly, System.Linq.Expressions.dll, which provides LINQ support to .NET Compact Framework 3.5. In order to use the full LINQ functionality including optimisation, add a reference to System.Linq.Expressions.dll in your project and enjoy.<br> <br> System.Linq.Expressions.dll can be found in bin\compact-3.5 folder of your distribution. You can also examine the code in src\Libs\compact-3.5\System.Linq.Expressions or db4o <a href="https://source.db4o.com/db4o/trunk/db4o.net/Libs/compact-3.5/System.Linq.Expressions/" target="_blank">SVN</a> .<br> <br> <br> <br> <br> <br> <a name="SODAQueryAPI"></a><br> </ul> <a name="outline156"></a><br><h2>4.4. SODA Query API</h2><br> The SODA query API is db4o's low level querying API, allowing direct access to nodes of query graphs. Since SODA uses strings to identify fields, it is neither perfectly typesafe nor compile-time checked and it also is quite verbose to write.<br> <br> For most applications <a href="Linq.html#LINQ">LINQ </a> and<a href="Query.html#NativeQueries">Native Queries</a> will be the better querying interface.<br> <br> However there can be applications where dynamic generation of queries is required, that's why SODA is explained here.<br> <br> <ul> <a name="outline157"></a><br><h2>4.4.1. Simple queries</h2><br> Let's see how our familiar QBE queries are expressed with SODA. A new Query object is created through the #Query() method of the ObjectContainer and we can add Constraint instances to it. To find all Pilot instances, we constrain the query with the Pilot class object.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveAllPilots<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> IObjectSet result = query.Execute();<br> 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.chapter1.QueryExample", "retrieveAllPilots")' /></td></tr></table> <br> <br> Basically, we are exchanging our 'real' prototype for a meta description of the objects we'd like to hunt down: a<b> query graph</b> made up of query nodes and constraints. A query node is a placeholder for a candidate object, a constraint decides whether to add or exclude candidates from the result.<br> <br> Our first simple graph looks like this.<br> <br> <img border="0" src="querygraph/1.gif" /><br> <br> We're just asking any candidate object (here: any object in the database) to be of type Pilot to aggregate our result.<br> <br> To retrieve a pilot by name, we have to further constrain the candidate pilots by descending to their name field and constraining this with the respective candidate String.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrievePilotByName<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_name").Constrain("Michael Schumacher");<br> IObjectSet result = query.Execute();<br> 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.chapter1.QueryExample", "retrievePilotByName")' /></td></tr></table> <br> <br> What does #Descend mean here? Well, just as we did in our 'real' prototypes, we can attach constraints to child members of our candidates.<br> <br> <br> <img border="0" src="querygraph/2net.gif" /><br> <br> So a candidate needs to be of type Pilot and have a member named'_name' that is equal to the given String to be accepted for the result.<br> <br> Note that the class constraint is not required: If we left it out, we would query for all objects that contain a'_name' member with the given value. In most cases this will not be the desired behavior, though.<br> <br> Finding a pilot by exact points is analogous.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrievePilotByExactPoints<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_points").Constrain(100);<br> IObjectSet result = query.Execute();<br> 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.chapter1.QueryExample", "retrievePilotByExactPoints")' /></td></tr></table> <br> <br> <a name="outline158"></a><br><h2>4.4.2. Advanced queries</h2><br> Now there are occasions when we don't want to query for exact field values, but rather for value ranges, objects not containing given member values, etc. This functionality is provided by the Constraint API.<br> <br> First, let's negate a query to find all pilots who are not Michael Schumacher:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveByNegation<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_name").Constrain("Michael Schumacher").Not();<br> IObjectSet result = query.Execute();<br> 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.chapter1.QueryExample", "retrieveByNegation")' /></td></tr></table> <br> <br> Where there is negation, the other boolean operators can't be too far.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveByConjunction<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> IConstraint constr = query.Descend("_name")<br> .Constrain("Michael Schumacher");<br> query.Descend("_points")<br> .Constrain(99).And(constr);<br> IObjectSet result = query.Execute();<br> 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.chapter1.QueryExample", "retrieveByConjunction")' /></td></tr></table> <br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveByDisjunction<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> IConstraint constr = query.Descend("_name")<br> .Constrain("Michael Schumacher");<br> query.Descend("_points")<br> .Constrain(99).Or(constr);<br> IObjectSet result = query.Execute();<br> 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.chapter1.QueryExample", "retrieveByDisjunction")' /></td></tr></table> <br> <br> We can also constrain to a comparison with a given value.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveByComparison<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_points")<br> .Constrain(99).Greater();<br> IObjectSet result = query.Execute();<br> 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.chapter1.QueryExample", "retrieveByComparison")' /></td></tr></table> <br> <br> The query API also allows to query for field default values. <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveByDefaultFieldValue<br> Pilot somebody = new Pilot("Somebody else", 0);<br> db.Store(somebody);<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_points").Constrain(0);<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> db.Delete(somebody);</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.chapter1.QueryExample", "retrieveByDefaultFieldValue")' /></td></tr></table> <br> <br> It is also possible to have db4o sort the results.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveSorted<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_name").OrderAscending();<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> query.Descend("_name").OrderDescending();<br> result = query.Execute();<br> 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.chapter1.QueryExample", "retrieveSorted")' /></td></tr></table> <br> <br> All these techniques can be combined arbitrarily, of course. Please try it out. There still may be cases left where the predefined query API constraints may not be sufficient - don't worry, you can always let db4o run any arbitrary code that you provide in an Evaluation. Evaluations will be discussed in a <a href="Evaluations.html#Evaluations">later chapter</a>.<br> <br> To prepare for the next chapter, let's clear the database.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// clearDatabase<br> IObjectSet result = db.QueryByExample(typeof(Pilot));<br> foreach (object item in result)<br> {<br> db.Delete(item);<br> }</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.chapter1.QueryExample", "clearDatabase")' /></td></tr></table> <br> <br> <a name="outline159"></a><br><h2>4.4.3. Conclusion</h2>Now you have been provided with the following alternative approaches to query db4o databases: Query-By-Example,.? net LINQ, Native Queries, SODA.<br> <br> Which one is the best to use? Some hints:<br> - LINQ is a standard typesafe queries for .NET languages and is recommended for use with .NET version of db4o.<br> - Native queries are targeted to be the primary interface for db4o, so they should be preferred.<br> - With the current state of the db4o query optimizer there may be queries that will execute faster in SODA style, so it can be used to tune applications. SODA can also be more convenient for constructing dynamic queries at runtime.<br> - Query-By-Example is nice for simple one-liners, but restricted in functionality. If you like this approach, use it as long as it suits your application's needs.<br> <br> Of course you can mix these strategies as needed.<br> <br> We have finished our walkthrough and seen the various ways db4o provides to pose queries. But our domain model is not complex at all, consisting of one class only. Let's have a look at the way db4o handles object associations in the <a href="Structured.html#Structured">next chapter</a> .<br> <br> <a name="outline160"></a><br><h2>4.4.4. 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;<br> namespace Db4odoc.Tutorial.F1.Chapter1<br> {<br> public class QueryExample : 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> using(IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))<br> {<br> StoreFirstPilot(db);<br> StoreSecondPilot(db);<br> RetrieveAllPilots(db);<br> RetrievePilotByName(db);<br> RetrievePilotByExactPoints(db);<br> RetrieveByNegation(db);<br> RetrieveByConjunction(db);<br> RetrieveByDisjunction(db);<br> RetrieveByComparison(db);<br> RetrieveByDefaultFieldValue(db);<br> RetrieveSorted(db); <br> ClearDatabase(db);<br> }<br> }<br> <br> public static void StoreFirstPilot(IObjectContainer db)<br> {<br> Pilot pilot1 = new Pilot("Michael Schumacher", 100);<br> db.Store(pilot1);<br> Console.WriteLine("Stored {0}", pilot1);<br> }<br> <br> public static void StoreSecondPilot(IObjectContainer db)<br> {<br> Pilot pilot2 = new Pilot("Rubens Barrichello", 99);<br> db.Store(pilot2);<br> Console.WriteLine("Stored {0}", pilot2);<br> }<br> <br> public static void RetrieveAllPilots(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> }<br> <br> public static void RetrievePilotByName(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_name").Constrain("Michael Schumacher");<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> }<br> <br> public static void RetrievePilotByExactPoints(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_points").Constrain(100);<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> }<br> <br> public static void RetrieveByNegation(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_name").Constrain("Michael Schumacher").Not();<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> }<br> <br> public static void RetrieveByConjunction(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> IConstraint constr = query.Descend("_name")<br> .Constrain("Michael Schumacher");<br> query.Descend("_points")<br> .Constrain(99).And(constr);<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> }<br> <br> public static void RetrieveByDisjunction(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> IConstraint constr = query.Descend("_name")<br> .Constrain("Michael Schumacher");<br> query.Descend("_points")<br> .Constrain(99).Or(constr);<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> }<br> <br> public static void RetrieveByComparison(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_points")<br> .Constrain(99).Greater();<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> }<br> <br> public static void RetrieveByDefaultFieldValue(IObjectContainer db)<br> {<br> Pilot somebody = new Pilot("Somebody else", 0);<br> db.Store(somebody);<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_points").Constrain(0);<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> db.Delete(somebody);<br> }<br> <br> public static void RetrieveSorted(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Pilot));<br> query.Descend("_name").OrderAscending();<br> IObjectSet result = query.Execute();<br> ListResult(result);<br> query.Descend("_name").OrderDescending();<br> result = query.Execute();<br> ListResult(result);<br> }<br> <br> public static void ClearDatabase(IObjectContainer db)<br> {<br> IObjectSet result = db.QueryByExample(typeof(Pilot));<br> foreach (object item in result)<br> {<br> db.Delete(item);<br> }<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>