|
3. Query API
We have already seen how to retrieve objects from db4o via QBE. While this approach is easy and intuitive, there are situations where it is not sufficient.
- There are queries that simply cannot be expressed with QBE: Retrieve all pilots with more than 100 points, for example.
- Creating a prototype object may have unwanted side effects.
- We may want to query for field default values.
db4o provides a dedicated query API that can be used in those cases.
We need some pilots in our database again to explore it.
Pilot pilot1=new Pilot("Michael Schumacher",100);
db.set(pilot1);
System.out.println("Stored "+pilot1);
| |
Pilot pilot2=new Pilot("Rubens Barrichello",99);
db.set(pilot2);
System.out.println("Stored "+pilot2);
| |
3.1. Simple queries
First, let's see how our familiar QBE queries are expressed within the query API. This is done by retrieving a 'fresh' Query object from the ObjectContainer and adding Constraint instances to it. To find all Pilot instances, we constrain the query with the Pilot class object.
Query query=db.query();
query.constrain(Pilot.class);
ObjectSet result=query.execute();
Util.listResult(result);
| |
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.
Query query=db.query();
query.constrain(Pilot.class);
query.descend("name").constrain("Michael Schumacher");
ObjectSet result=query.execute();
Util.listResult(result);
| |
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.
Finding a pilot by exact points is analogous, we just have to cross the Java primitive/object divide.
Query query=db.query();
query.constrain(Pilot.class);
query.descend("points").constrain(new Integer(100));
ObjectSet result=query.execute();
Util.listResult(result);
| |
3.2. Advanced queries
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.
First, let's negate a query to find all pilots who are not Michael Schumacher:
Query query=db.query();
query.constrain(Pilot.class);
query.descend("name").constrain("Michael Schumacher").not();
ObjectSet result=query.execute();
Util.listResult(result);
| |
Where there is negation, the other boolean operators can't be too far.
Query query=db.query();
query.constrain(Pilot.class);
Constraint constr=query.descend("name")
.constrain("Michael Schumacher");
query.descend("points")
.constrain(new Integer(99)).and(constr);
ObjectSet result=query.execute();
Util.listResult(result);
| |
Query query=db.query();
query.constrain(Pilot.class);
Constraint constr=query.descend("name")
.constrain("Michael Schumacher");
query.descend("points")
.constrain(new Integer(99)).or(constr);
ObjectSet result=query.execute();
Util.listResult(result);
| |
We can also constrain to a comparison with a given value.
Query query=db.query();
query.constrain(Pilot.class);
query.descend("points")
.constrain(new Integer(99)).greater();
ObjectSet result=query.execute();
Util.listResult(result);
| |
The query API also allows to query for field default values.
Pilot somebody=new Pilot("Somebody else",0);
db.set(somebody);
Query query=db.query();
query.constrain(Pilot.class);
query.descend("points").constrain(new Integer(0));
ObjectSet result=query.execute();
Util.listResult(result);
db.delete(somebody);
| |
It is also possible to have db4o sort the results.
Query query=db.query();
query.constrain(Pilot.class);
query.descend("name").orderAscending();
ObjectSet result=query.execute();
Util.listResult(result);
query.descend("name").orderDescending();
result=query.execute();
Util.listResult(result);
| |
All these techniques can be combined arbitrarily, of course. Please try it out.
To prepare for the next chapter, let's clear the database.
ObjectSet result=db.get(new Pilot(null,0));
while(result.hasNext()) {
db.delete(result.next());
}
| |
3.3. Conclusion
Now we know how to build arbitrarily complex 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 next chapter.
3.4. Full source
package com.db4o.f1.chapter1;
import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.f1.Util;
import com.db4o.query.Constraint;
import com.db4o.query.Query;
public class QueryExample {
public static void main(String[] args) {
ObjectContainer db=Db4o.openFile(Util.YAPFILENAME);
try {
storeFirstPilot(db);
storeSecondPilot(db);
retrieveAllPilots(db);
retrievePilotByName(db);
retrievePilotByExactPoints(db);
retrieveByNegation(db);
retrieveByConjunction(db);
retrieveByDisjunction(db);
retrieveByComparison(db);
retrieveByDefaultFieldValue(db);
retrieveSorted(db);
clearDatabase(db);
}
finally {
db.close();
}
}
public static void storeFirstPilot(ObjectContainer db) {
Pilot pilot1=new Pilot("Michael Schumacher",100);
db.set(pilot1);
System.out.println("Stored "+pilot1);
}
public static void storeSecondPilot(ObjectContainer db) {
Pilot pilot2=new Pilot("Rubens Barrichello",99);
db.set(pilot2);
System.out.println("Stored "+pilot2);
}
public static void retrieveAllPilots(ObjectContainer db) {
Query query=db.query();
query.constrain(Pilot.class);
ObjectSet result=query.execute();
Util.listResult(result);
}
public static void retrievePilotByName(ObjectContainer db) {
Query query=db.query();
query.constrain(Pilot.class);
query.descend("name").constrain("Michael Schumacher");
ObjectSet result=query.execute();
Util.listResult(result);
}
public static void retrievePilotByExactPoints(
ObjectContainer db) {
Query query=db.query();
query.constrain(Pilot.class);
query.descend("points").constrain(new Integer(100));
ObjectSet result=query.execute();
Util.listResult(result);
}
public static void retrieveByNegation(ObjectContainer db) {
Query query=db.query();
query.constrain(Pilot.class);
query.descend("name").constrain("Michael Schumacher").not();
ObjectSet result=query.execute();
Util.listResult(result);
}
public static void retrieveByConjunction(ObjectContainer db) {
Query query=db.query();
query.constrain(Pilot.class);
Constraint constr=query.descend("name")
.constrain("Michael Schumacher");
query.descend("points")
.constrain(new Integer(99)).and(constr);
ObjectSet result=query.execute();
Util.listResult(result);
}
public static void retrieveByDisjunction(ObjectContainer db) {
Query query=db.query();
query.constrain(Pilot.class);
Constraint constr=query.descend("name")
.constrain("Michael Schumacher");
query.descend("points")
.constrain(new Integer(99)).or(constr);
ObjectSet result=query.execute();
Util.listResult(result);
}
public static void retrieveByComparison(ObjectContainer db) {
Query query=db.query();
query.constrain(Pilot.class);
query.descend("points")
.constrain(new Integer(99)).greater();
ObjectSet result=query.execute();
Util.listResult(result);
}
public static void retrieveByDefaultFieldValue(
ObjectContainer db) {
Pilot somebody=new Pilot("Somebody else",0);
db.set(somebody);
Query query=db.query();
query.constrain(Pilot.class);
query.descend("points").constrain(new Integer(0));
ObjectSet result=query.execute();
Util.listResult(result);
db.delete(somebody);
}
public static void retrieveSorted(ObjectContainer db) {
Query query=db.query();
query.constrain(Pilot.class);
query.descend("name").orderAscending();
ObjectSet result=query.execute();
Util.listResult(result);
query.descend("name").orderDescending();
result=query.execute();
Util.listResult(result);
}
public static void clearDatabase(ObjectContainer db) {
ObjectSet result=db.get(new Pilot(null,0));
while(result.hasNext()) {
db.delete(result.next());
}
}
}
| |
-- generated by Doctor courtesy of db4objecs Inc.
|