Peers are an Object Relation mapping tool, built on top of Village that gives you access to a relational database via Java objects. Peers act on a somewhat lower level than other O-R mapping tools like Castor or Osage. This means that you have to do some coding by hand, but it allows for the most flexible solution.
Peers use Torque's Database adaptor classes that make uniform connection to a wide range of databases possible. If your database is not supported you can read the Database Adapter docs on how to create a new adaptor for your database.
Peers make use of a DatabaseMap class that holds internal data about the relational schema. You will seldom, if ever, need to work with the DatabaseMap class. It is used internally by Peers to discover information about the database at runtime.
There is exactly one DatabaseMap for each relational database that you connect to. You may wish to connect to more than one database in your application. You should then have one DatabaseMap for each of the databases.
DatabaseMaps are constructed by classes called MapBuilders. Torque generates MapBuilder classes for each of the tables in your schema.
Everything in Peers resolve around Peer classes. A Peer class has a one-to-one mapping to a Database table. You use each table's associated Peer class to do operations on that table. Peer classes are generated for you automatically.
Peer classes have static methods only, so you would never create objects of Peer classes. It is not necessary to have objects on this level because of the one-to-one mapping with a table. Peer methods are thread safe.
A Data Object holds information about a single row of a specific table. Data Objects can be generated automatically for you. It takes the form of Bean properties for each field of the table.
Data Objects are used almost exclusively with their related Peer classes. Where peer classes "wrap around" around a database table, a Data Object "wrap around" individual rows of the table. The two always go together.
You normally use Data Objects in one of two ways. The most common way is to extract data after you called a doSelect on a Peer class. The doSelect method returns a vector of Data Objects that holds the data of the resultset. Secondly you can create Data Objects and pass it to the overloaded doInsert and doUpdate methods of the relevant Peer class.
Criteria is an abstraction of the criteria of an sql query. We use criteria objects to specify the criteria of a sql statement. The database adaptor classes contains information on how this Criteria object will be translated to different flavours of sql.
Criteria is in effect a map of field names and values that forms the criteria of a query. By default the comparison is equals (=) but you can define any comparison operator (<, >, <=, > =, IN, etc.).
Criteria can also be used to do some other sql function like ORDER BY or DISTINCT. If Criteria is too limited for your purposes (which should not happen often) you are still free to use raw sql queries.
There is more information on the use of the Criteria class in a seperate Criteria Howto.
One of the cool features of Peers is the ID Broker. ID Broker is used to automatically create unique primary keys for tables. The ID Broker has support for auto-increment fields like in MySQL; sequence generators like in Oracle or if neither is supported it creates id's from a database table called id_table.
Of course Torque also supports using the ID generation provided by the
underlying database system - just set the idMethod
attributes
as desired in your schema.
The ID Broker is used in the underlying Peer code. After you have generated your object model classes you need not worry about it anymore.
All the examples on this section will be based on the following schema:
CREATE TABLE category ( category_id INTEGER NOT NULL AUTO_INCREMENT, name VARCHAR (100), PRIMARY KEY(category_id) ); CREATE TABLE item ( item_id INTEGER NOT NULL AUTO_INCREMENT, name VARCHAR (100), price INTEGER NOT NULL, category_id INTEGER NOT NULL, PRIMARY KEY(item_id), FOREIGN KEY (category_id) REFERENCES category (category_id) );
Peer classes are typically generated by invoking the torque:om
goal using the Torque maven-plugin.
Peer class source code is generated based on the project database schema. The definition of this schema is in XML, and the associated DTD is included with the Torque generator.
For the schema described above, the XML would look something like
Probably the most common use of Peers is to select data from a database. If we want to extract all the Categories from the database we can use the following code. Because we want all the objects we don't need to add anything special to the Criteria.
Criteria crit = new Criteria(); List categories = CategoryPeer.doSelect(crit);
If you want to select all the items of a certain Category you need to add it to the Criteria object. For example we need all the items from the Category with id 2.
Criteria crit = new Criteria(); crit.add(ItemPeer.CATEGORY_ID,2); List items = ItemPeer.doSelect(crit);
To do an insert we need to add all the fields to the criteria objects. Note that the id field is not added to the Criteria. It is taken care of by underlying database system (or perhaps the ID BROKER when it is in use). The object that is returned by doInsert is the id of the newly added row.
Criteria crit = new Criteria(); crit.add(CategoryPeer.NAME, "New Category"); Object o = CategoryPeer.doInsert(crit);
We can also use the overloaded method to add a new Data Object. Note that once again we don't set the id - this is done for us automatically.
Item itm = new Item(); itm.setName("New Item"); itm.setPrice(100); itm.setCategoryId(1); Object o = ItemPeer.doInsert(itm);
Updates works pretty much the same as inserts. You just need to call the doUpdate method from your Peer class. Just keep in mind that you must add an id column if you wish to do updates.
Deletes work much in the same way as a select. If you, for example, want to delete the item with id = 3 then you simply add it to the Criteria and call doDelete.
Criteria crit = new Criteria(); crit.add(ItemPeer.ITEM_ID, 3); ItemPeer.doDelete(crit);
In this section I'm going to try and explain a bit more about using Peers than just run of the mill selects, inserts and updates. However, this is by no means the be-all and end-all of Peer usage. It is just some ideas that I have found to work well.
I found that it saves a bit of duplicate work if you add some utility methods to your Peer class. The first method is very straightforward. It is used to select all the entries from a table and I usually call it doSelectAll().
public class CategoryPeer extends BaseCategoryPeer { static public List doSelectAll() throws Exception { Criteria crit = new Criteria(); return = doSelect(crit); } }
The next method is used to select all the objects of a database relation. For example the relation between a category and items. Say for example that you routinely need to select all the items of a given category. We add a doSelectForCategory to the ItemPeer class.
public class ItemPeer extends BaseItemPeer { static public List doSelectForCategory(int categoryid) throws Exception { Criteria crit = new Criteria(); crit.add(CATEGORY_ID, categoryid); return doSelect(crit); } }
Sometimes you would like to have relations between tables be available in the Peer objects. We defined a foreign key relationship in the Item table in the XML schema. This means getCategory() and setCategory() methods are generated in the BaseItem class. In a relational database the foreign key allows us to access the Category row that is associated with a specific Item row. In the object model, an Item class represents one row from the Item table. The getCategory() method will return a reference to a Category class that represents the associated row from the Category table.
A doSelectJoinCategory() method is generated for the BaseItemPeer class. It creates the join between tables and sets the Category reference in the Item class. It can be used like this:
// select all Items with their associated Category Criteria crit = new Criteria(); List items = ItemPeer.doSelectJoinCategory(crit); // access the Category associated with the first Item in the list Item itm = (Item) items.get(0); Category cat = itm.getCategory();
We can also constrain the selected rows just as we would with a normal doSelect() method:
// select only Items with a category of 2 Criteria crit = new Criteria(); crit.add(Item.CATEGORY_ID, 2); List items = ItemPeer.doSelectJoinCategory(crit); // get the name of category 2 Item itm = (Item) items.get(0); Category cat = itm.getCategory(); String name = cat.getName();
This is an example of a complex SQL query and the code you should use to create it:
There are a lot more examples of how to use the Criteria class in the Criteria Howto.