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.
For most applications Native Queriesupdated will be the better querying interface.
However there can be applications where dynamic generation of queries is required, that's why SODA is explained here.
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.
01public static void RetrieveAllPilots() 02
{ 03
IObjectContainer db = Db4oFactory.OpenFile(YapFileName); 04
try 05
{ 06
IQuery query = db.Query(); 07
query.Constrain(typeof(Pilot)); 08
IObjectSet result = query.Execute(); 09
ListResult(result); 10
} 11
finally 12
{ 13
db.Close(); 14
} 15
}
01Public Shared Sub RetrieveAllPilots() 02
Dim db As IObjectContainer = Db4oFactory.OpenFile(Db4oFileName) 03
Try 04
Dim query As IQuery = db.Query() 05
query.Constrain(GetType(Pilot)) 06
Dim result As IObjectSet = query.Execute() 07
ListResult(result) 08
Finally 09
db.Close() 10
End Try 11
End Sub
Basically, we are exchanging our 'real' prototype for a meta description of the objects we'd like to hunt down: a query graph 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.
Our first simple graph looks like this.
We're just asking any candidate object (here: any object in the database) to be of type Pilot to aggregate our 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.
1public static void RetrievePilotByName(IObjectContainer db) 2
{ 3
IQuery query = db.Query(); 4
query.Constrain(typeof(Pilot)); 5
query.Descend("_name").Constrain("Michael Schumacher"); 6
IObjectSet result = query.Execute(); 7
ListResult(result); 8
}
1Public Shared Sub RetrievePilotByName(ByVal db As IObjectContainer) 2
Dim query As IQuery = db.Query() 3
query.Constrain(GetType(Pilot)) 4
query.Descend("_name").Constrain("Michael Schumacher") 5
Dim result As IObjectSet = query.Execute() 6
ListResult(result) 7
End Sub
What does 'descend' mean here? Well, just as we did in our 'real' prototypes, we can attach constraints to child members of our candidates.
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.
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.
1public static void RetrievePilotByExactPoints(IObjectContainer db) 2
{ 3
IQuery query = db.Query(); 4
query.Constrain(typeof(Pilot)); 5
query.Descend("_points").Constrain(100); 6
IObjectSet result = query.Execute(); 7
ListResult(result); 8
}
1Public Shared Sub RetrievePilotByExactPoints(ByVal db As IObjectContainer) 2
Dim query As IQuery = db.Query() 3
query.Constrain(GetType(Pilot)) 4
query.Descend("_points").Constrain(100) 5
Dim result As IObjectSet = query.Execute() 6
ListResult(result) 7
End Sub
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:
1public static void RetrieveByNegation(IObjectContainer db) 2
{ 3
IQuery query = db.Query(); 4
query.Constrain(typeof(Pilot)); 5
query.Descend("_name").Constrain("Michael Schumacher").Not(); 6
IObjectSet result = query.Execute(); 7
ListResult(result); 8
}
1Public Shared Sub RetrieveByNegation(ByVal db As IObjectContainer) 2
Dim query As IQuery = db.Query() 3
query.Constrain(GetType(Pilot)) 4
query.Descend("_name").Constrain("Michael Schumacher").[Not]() 5
Dim result As IObjectSet = query.Execute() 6
ListResult(result) 7
End Sub
Where there is negation, the other boolean operators can't be too far.
01public static void RetrieveByConjunction(IObjectContainer db) 02
{ 03
IQuery query = db.Query(); 04
query.Constrain(typeof(Pilot)); 05
IConstraint constr = query.Descend("_name") 06
.Constrain("Michael Schumacher"); 07
query.Descend("_points") 08
.Constrain(99).And(constr); 09
IObjectSet result = query.Execute(); 10
ListResult(result); 11
}
1Public Shared Sub RetrieveByConjunction(ByVal db As IObjectContainer) 2
Dim query As IQuery = db.Query() 3
query.Constrain(GetType(Pilot)) 4
Dim constr As Constraint = query.Descend("_name").Constrain("Michael Schumacher") 5
query.Descend("_points").Constrain(99).Or(constr) 6
Dim result As IObjectSet = query.Execute() 7
ListResult(result) 8
End Sub
01public static void RetrieveByDisjunction(IObjectContainer db) 02
{ 03
IQuery query = db.Query(); 04
query.Constrain(typeof(Pilot)); 05
IConstraint constr = query.Descend("_name") 06
.Constrain("Michael Schumacher"); 07
query.Descend("_points") 08
.Constrain(99).Or(constr); 09
IObjectSet result = query.Execute(); 10
ListResult(result); 11
}
1Public Shared Sub RetrieveByDisjunction(ByVal db As IObjectContainer) 2
Dim query As IQuery = db.Query() 3
query.Constrain(GetType(Pilot)) 4
Dim constr As Constraint = query.Descend("_name").Constrain("Michael Schumacher") 5
query.Descend("_points").Constrain(99).Or(constr) 6
Dim result As IObjectSet = query.Execute() 7
ListResult(result) 8
End Sub
We can also constrain to a comparison with a given value.
1public static void RetrieveByComparison(IObjectContainer db) 2
{ 3
IQuery query = db.Query(); 4
query.Constrain(typeof(Pilot)); 5
query.Descend("_points") 6
.Constrain(99).Greater(); 7
IObjectSet result = query.Execute(); 8
ListResult(result); 9
}
1Public Shared Sub RetrieveByComparison(ByVal db As IObjectContainer) 2
Dim query As IQuery = db.Query() 3
query.Constrain(GetType(Pilot)) 4
query.Descend("_points").Constrain(99).Greater() 5
Dim result As IObjectSet = query.Execute() 6
ListResult(result) 7
End Sub
The query API also allows to query for field default values.
01public static void RetrieveByDefaultFieldValue(IObjectContainer db) 02
{ 03
Pilot somebody = new Pilot("Somebody else", 0); 04
db.Set(somebody); 05
IQuery query = db.Query(); 06
query.Constrain(typeof(Pilot)); 07
query.Descend("_points").Constrain(0); 08
IObjectSet result = query.Execute(); 09
ListResult(result); 10
db.Delete(somebody); 11
}
01Public Shared Sub RetrieveByDefaultFieldValue(ByVal db As IObjectContainer) 02
Dim somebody As Pilot = New Pilot("Somebody else", 0) 03
db.Set(somebody) 04
Dim query As IQuery = db.Query() 05
query.Constrain(GetType(Pilot)) 06
query.Descend("_points").Constrain(0) 07
Dim result As IObjectSet = query.Execute() 08
ListResult(result) 09
db.Delete(somebody) 10
End Sub
It is also possible to have db4o sort the results.
01public static void RetrieveSorted(IObjectContainer db) 02
{ 03
IQuery query = db.Query(); 04
query.Constrain(typeof(Pilot)); 05
query.Descend("_name").OrderAscending(); 06
IObjectSet result = query.Execute(); 07
ListResult(result); 08
query.Descend("_name").OrderDescending(); 09
result = query.Execute(); 10
ListResult(result); 11
}
01Public Shared Sub RetrieveSorted(ByVal db As IObjectContainer) 02
Dim query As IQuery = db.Query() 03
query.Constrain(GetType(Pilot)) 04
query.Descend("_name").OrderAscending() 05
Dim result As IObjectSet = query.Execute() 06
ListResult(result) 07
query.Descend("_name").OrderDescending() 08
result = query.Execute() 09
ListResult(result) 10
End Sub
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 Evaluations chapter.