|
More powerful query support
One of the major drawbacks of early versions of db4o was that QBE provides fairly limited querying capability. For example, you couldn't run a query like "all players with batting average greater than .300". db4o now includes the S.O.D.A. API to provide querying that comes much closer to the power of SQL. An instance of the Query class represents a node in a query criteria graph to which constraints can be applied. A node can represent a class, multiple classes, or a class attribute.
The following code demonstrates how to do the query described in the previous paragraph. We define a query graph node and constrain it to the Player class. This means that the query will only return Player objects. We then descend the graph to find a node representing an attribute named “battingAverage” and constrain this to be greater than 0.3. Finally, the query is executed to return all objects in the database that match the constraints.
Query q = db.query();
q.constrain(Player.class);
q.descend("battingAverage").constrain(new Float(0.3f)).greater();
ObjectSet result = q.execute();
At first glance, this performs a similar query to an SQL query, like this:
SELECT * FROM players WHERE battingAverage > 0.3
However, the design of the Player class allows inverse relationships to be created between Team and Player objects, as shown in the test data. A Team has a reference to a list of Player objects, while each Player has a reference to a Team. This means that the result of this query contains Player and Team objects. The code below demonstrates this:
System.out.println(result.size());
while(result.hasNext()) {
// Print Player
Player p = (Player) result.next();
System.out.println(p);
// Getting Player also gets Team - print Team
Team t = p.getTeam();
System.out.println(t);
}
Output:
2
Adrian Beltre:0.334
Dodgers
Barry Bonds:0.362
Giants
The query is now similar to an SQL query, like this:
SELECT teams.name, players.name, players.battingAverage FROM teams, players
WHERE teams.teamID = players.playerID
AND battingAverage > 0.3
This worked because the inverse relationship was designed into the object model. Object databases are navigational: you can only retrieve data following the direction of predefined relationships. Relational databases, on the other hand, have no directionality in their table joins and therefore allow more flexibility for ad-hoc queries. However, given the right object relationships, related objects can be retrieved from the object database with very little programming effort. The database model and the application object model are identical, so there is no need for the programmer to think differently about the data. If you can get the Team for a given Player when the objects are in memory, you can do the same from the database. |
|