Book Image

Tapestry 5: Building Web Applications

Book Image

Tapestry 5: Building Web Applications

Overview of this book

Table of Contents (17 chapters)
Tapestry 5
Credits
About the Author
About the Reviewers
Preface
Foreword
Where to Go Next

The Main Operations


To create the database, we use the following line of code:

ObjectContainer db =
Db4o.openFile("C:\tapestry5\data\celebrities.dat");

If such a file already exists, db4o will just open it, otherwise it will create a new file.

Perhaps the simplest thing we can do is to retrieve all the celebrities stored in the database. Here is how the getAllCelebrities method of the new data source will look:

public List<Celebrity> getAllCelebrities()
{
return db.query(Celebrity.class);
}

We just tell the database the representatives of which class we want to retrieve, and it returns a list, returning all the available objects of that class.

If however we want to retrieve a specific object, we'll need to do a little more work. First of all, we need to select one of the two main approaches to querying a db4o database—Query by Example (QBE) or Native Query. QBE is a very simple approach, but it is limited in a few ways (read the tutorial for details). Anyway, let's use QBE for the getCelebrityById method. Here is how this method will look:

public Celebrity getCelebrityById(long id)
{
Celebrity proto = new Celebrity();
proto.setId(id);
ObjectSet result = db.get(proto);
if (result.hasNext()) return (Celebrity)result.next();
return null;
}

First of all, we need to create a prototype object of the same type as the object, or objects we are going to retrieve:

Celebrity proto = new Celebrity();

Next, we need to set some of the properties of the prototype to the values we want to see in the returned objects. The database will return all the objects that match all non-default values of the prototype's properties. In our example we want to find a celebrity with a certain ID, so we set the ID property of the prototype to the desired value:

proto.setId(id);

Then we pass the prototype to the get method, and the result will be provided as an ObjectSet:

ObjectSet result = db.get(proto);

We can then check whether there is something in the result by using the hasNext method and retrieving that next object as the example shows.

Storing an object in the database is also quite simple. This is how addCelebrity method looks:

public void addCelebrity(Celebrity c)
{
db.set(c);
}

However, there is one potential problem with such an implementation. Say we have just saved a Celebrity object containing the data for Bill Clinton. Then we created another object with exactly the same data and saved it too. For db4o, as this database operates with objects, any two distinct objects are different, so it will just save the second Bill Clinton object without any doubt, and we shall have two objects with the same data, which is probably not what we really want.

To avoid such a problem, we need to check whether an object with exactly the same values already exists before saving an object to the database. So here is a more robust implementation of the addCelebrity method:

public void addCelebrity(Celebrity c)
{
ObjectSet result = db.get(c);
if (!result.hasNext())
{
db.set(c);
}
}

I cannot finish this demonstration of db4o without showing you an example of a Native Query—the approach we are most often going to use in real life applications. This approach isn't much more complex than QBE, by the way, but more efficient and powerful.

Let us, just for the purposes of this appendix, implement the getRange(int indexFrom, int indexTo) method in a way slightly different from how it was dealt with in the main body of the book. Say we want this method to return a list of Celebrity objects whose ID property is greater than or equal to the indexFrom parameter and less than or equal to the indexTo parameter. This is how we can define such a condition in Java:

celebrity.getId() >= indexFrom &&
celebrity.getId() <= indexTo

For this condition to work in our native query, we need to put it into the match method of an implementation of the Predicate interface. Then we pass this Predicate to the query method of our database. To do all this, the tutorial that comes with db4o uses the "anonymous inner class" feature of the Java language that allows creating an implementation of an interface "on-the-fly". Let's follow the same approach:

public List<Celebrity> getRange(final int indexFrom,
final int indexTo)
{
List<Celebrity> result =
db.query(new Predicate<Celebrity>()
{
public boolean match(Celebrity celebrity)
{
return celebrity.getId() >= indexFrom &&
celebrity.getId() <= indexTo;
}
});
return result;
}

This way, in pure Java, we can define any kind of condition, and there is no need to resort to any specialized query languages. By the way, we had to make method parameters final here since otherwise Java would not allow us to use them in an inner class.