db4o: Queries in Java or Queries Without LINQ

Before I continue with client-server concurrency I explain how to run queries against a db4o database without LINQ. Most of the stuff in db4o works on every platform. The API is nearly the same in Java and .NET, except the different naming-convections. The lucky .NET developers have one big advantage over Java, they have LINQ which is just awesome. The less lucky Java or C# 2.0 developers have to use other methods. So I’ll give an overview over the alternative query-methods. For this post I use Java instead of C# to avoid using LINQ by accident 😉

db4o-java-bff

(All posts of this series: the basics, activation, object-identity, transactions, persistent classes, single container concurrency, Queries in Java, C# 2.0, client-server concurrency, transparent persistence, adhoc query tools)

Native Queries

When you hear ‘Native Queries’ you might think that it is something like SQL. The language which is ‘native’ to the database. You’re wrong. It means that it’s ‘native’ to your programming language. So you write queries just as Java-Code. Native queries are in my opinion the best alternative to LINQ. Basically you pass a inner class (poor man’s closures) to the query-method. There you implement which criteria have to be fulfilled. A simple example:

List<SimpleObject> result = db.query(new Predicate<SimpleObject>() {
    @Override
    public boolean match(SimpleObject o) {
        return o.getNumber()>2;
    }
});
 

So this quite easy and natural. You just write your condition in the match-method of a predicate. A more complex example which also sorts the result:

List<ComplexObject> result2 = db.query(new Predicate<ComplexObject>() {
@Override
public boolean match(ComplexObject o) {
    return o.getVersion()==1
            && o.getKnowsAbout().getNumber()<2
            || o.getMightKnowsAlso()!=null;
}
},new QueryComparator<ComplexObject>() {
    public int compare(ComplexObject complexObject, ComplexObject complexObject1) {
        return complexObject.getKnowsAbout().getName().compareTo(complexObject1.getKnowsAbout().getName());
    }
}); 

Modern Java-IDEs collapse the verbose inner classes to readable little ‘closures’. Therefore it looks nicer in the real world. (Eclipse with lambda4jdt, IntelliJ 9)

native queries

native queries

Query By Example

In this query-type you give the database an object as an example. Then the database returns all objects which are similar to the given object.

An example. We create an new object with name ‘MyObject-3’ and the number 3. Then we pass it to db4o. As result we get all object which have the same name and number.

SimpleObject toSearchFor = new SimpleObject("MyObject-3",3);
final ObjectSet<Object> result1 = db.queryByExample(toSearchFor);

It’s simple but quite limiting. It’s might a suitable solution when you implement some kind of search-forms. Then you just can fill an object with values of the search-form and off you go. But you can imagine the limits. For example you cannot get the objects which have number==0. Because query by example only matches fields which differ from the default-value. For a int 0 is the default and you’re fucked. As far as I know there’s no way to express such condition by example. So you have to use other query-types.

System.out.println("-cannot get the object with Number=0---");
SimpleObject doesnotWork = new SimpleObject(0);
final ObjectSet<Object> result2 = db.queryByExample(doesnotWork);

query be example

query be example

SODA-Queries

Now SODA-Queries is the low level query API for db4o. Normally you don’t touch SODA unless you have some special scenarios. For example when you need to build queries very dynamically. Because of that I just mention it here but don’t give any examples (Maybe another time).

All other query-types, LINQ, Native-Queries and Query By Example are actually translated into SODA-queries. To achieve this db4o uses byte-code analysis and generates then SODA-queries. Simple queries are translated into SODA an run directly on the database. However more complex queries may cannot be optimized. Then db4o actually instantiates the objects and runs the query on the instances. For more details see here: LINQ-Optimization, Native-Query-Optimization

soda queries

soda queries

Conclusion

So, db4o supports a variety of query-types. In my opinion LINQ is the best one, but only available on then most recent .NET framework. Native queries is the second best choice. For special cases query be example might be an alternative. In the end everything is crunched down to SODA-Queries, which is the low level query API. Next time I cover the client-server-concurrency as promised =)

Java-Code: ComplexObject.java, Main.java, SimpleObject.java, Preconditions.java

Tagged on: ,

6 thoughts on “db4o: Queries in Java or Queries Without LINQ

  1. Pingback: Community News : New to db4o? Learn & Have Fun!

  2. suez

    Since you are probably the guy who has answered on my question at stackoverflow, I am quite happy to see, that you’ve got a blog (with neat, really bad drawn comics :D).
    You seem to know much more about db4o then I do, so I was wondering if you could help me with a problem.

    As I was mentioning at stackoverflow, I am trying to build SODA queries dynamically, by reading the fields and values to build my query nodes from a txt-file. And then linking them in the right way. This works perfectly fine if I query for fields of the same class.
    But usually your query will look more like this:
    “get objects from classA where field1=bla and form classB where field2=blabla”
    I can’t figure out to do that in a dynamic way and can’t find a clue in the db4o reference.
    I can’t even build such a query using the OME.
    Frankly I do not know if this is even possible. I can’t imagine that I am the only person with such
    a problem, but based on my googling I am.

    I could send you some code via mail or open up another question at stackoverflow if you wish.

  3. gamlerhart Post author

    Hi

    To the SODA question:
    Well unfortunately SODA is very limited in it’s query capabilities. So only can run very limited operations =(

    The query like: “get objects from classA where field1=bla and form classB where field2=blabla”

    What should it do? Return from both types, classA and classB. Well this is not possible with soda. SODA is basically limited to have some type in the root, only one =(

    To do this you would basically need to run two queries, one for classA, one for classB and merge them. That’s all you can do.

    Yeah, queries are not db4o strengths.

    Cheers

    Ronam

  4. suez

    Thanks for your answer.
    The think is, by the looks of it is possible to query for different classes, if these classes are inheriting from the same superclass somewhere along the hierarchy… So if I declare a class Human as root, Hero extending Human, Pilot and Captain extending Hero, I could query for all fields in all combinations. But, if I declare Object.class as root, nothings works… which seems quite strange to me, because Object is the superclass of all classes.

  5. gamlerhart Post author

    If you don’t specify any type, just leave that part out, you can query for any object which fulfills the specification. So if a object has the field with that value, it will be returned. However this type of query doesn’t use any index. Therefore it will be extremely slow on a reasonable sized database.

  6. suez

    Yeah, thats probably the solution I will stick with. Query times doen’t matter that much for me, as long as it’s faster then fileoperations on tousands of files.