Speedo Tutorial - Additional 1

 FinalLogo.jpg
 FinalLogo.jpg
  1. Object model
  2. Step 4 : queries
  3. Object model
  4. Step 5 : inheritance

Back to the Speedo tutorial home page



    In the first two chapters, we described basic jdo features and the mapping. In this chapter, we will learn to use advanced jdo features such as the queries and the inheritance.

Object model

   The step 4 deals with jdo queries. To illustrate jdo queries, we will work on the following object model (very simple by the way):
   

A Person is identified by his name and has a reference to his children (inner reference) and a reference to a contactDetails.
A ContactDetails is identified by its email.

The source code of the java classes is located in the org.objectweb.speedo.tutorial.pobjects.additional.queries package.


The queries.jdo file is as follows:

<!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" "jdo.dtd">
<jdo>
<package name="org.objectweb.speedo.tutorial.pobjects.additional.queries">

<class name="Person" identity-type="application">
<extension vendor-name="speedo" key="sql-name" value="T_ADDITIONAL_PERSON"/>
<field name="name" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="NAME"/>
</field>
<field name="age">
<extension vendor-name="speedo" key="sql-name" value="AGE"/>
</field>
<field name="children" persistence-modifier="persistent">
<collection element-type="Person"/>
</field>
<field name="contactDetails">
<extension vendor-name="speedo" key="target-foreign-keys" value="EMAIL:CD_EMAIL"/>
</field>
</class>

<class name="ContactDetails" identity-type="application">
<extension vendor-name="speedo" key="sql-name" value="T_ADDITIONAL_CONTACT_DETAILS"/>
<field name="email" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="EMAIL"/>
</field>
<field name="phone">
<extension vendor-name="speedo" key="sql-name" value="PHONE"/>
</field>
</class>

</package>
</jdo>


Top
 

Step 4 : queries

    In this step, we are going to use queries to retrieve Person persistent instances using several criteria.
    To perform such queries, we firstly create persistent objects in hte same way than in the 1-3 steps excepted the call to the makePersistentAll(Collection c) method. This method enables to         make a collection of objects persistent.
   
/**
* Create persistent objects
*/
public static void createObjects(PersistenceManager pm){
//create 6 persons
Person person1 = new Person("Grange Jean-Luc", 54, new ContactDetails("jeanluc.grange@wanadoo.fr", "1234567890"));
Person person2 = new Person("Bordes Raymond", 75, new ContactDetails("raymond.bordes@wanadoo.fr", "1234567890"));
Person person3 = new Person("Labbe Loic", 16, new ContactDetails("loic.labbe@wanadoo.fr", "1234567890"));
Person person4 = new Person("Lambert Celine", 19, new ContactDetails("celine.lambert@wanadoo.fr", "0987654321"));
Person person5 = new Person("Couture Zelie", 23, new ContactDetails("zelie.couture@wanadoo.fr", "0987654321"));
Person person6 = new Person("Landreau Vincent", 2, new ContactDetails("vincent.landreau@wanadoo.fr", "0987654321"));

person1.addChild(person4);
person1.addChild(person5);

person5.addChild(person6);

Collection persons = new ArrayList();
persons.add(person1);
persons.add(person2);
persons.add(person3);
persons.add(person4);
persons.add(person5);
persons.add(person6);

//make persistent all the persons using a collection
pm.currentTransaction().begin();
pm.makePersistentAll(persons);
pm.currentTransaction().commit();
pm.currentTransaction().commit();
}

    To execute a jdo query:
    The iterateExtent method shows how to use Extent to iterate over all the instances of a class:

//iterate over all the persons
public static void iterateExtent(PersistenceManager pm){
Extent extent = pm.getExtent(Person.class, true);
Iterator it = extent.iterator();
System.out.println( "All " + Person.class.getName() + " instances:");
while(it.hasNext()){
Person p = (Person) it.next();
System.out.println( p.toString());
}
extent.close(it);
}


    The basicQuery method shows how to build a basic query using a static parameter:

//retrieve all the under-20 persons
public static void basicQuery(PersistenceManager pm){
Query query = pm.newQuery(Person.class, "age < 20");
Collection results = (Collection)query.execute();
System.out.println( "Young persons (<20 years old) :");
Iterator it = results.iterator();
while(it.hasNext()){
Person p = (Person) it.next();
System.out.println( p.toString());
}
query.closeAll();
}


    The basicQueryOrdering method shows a way to organize the result set:

//retrieve all the over-25 persons with ordering
public static void basicQueryOrdering(PersistenceManager pm){
Query query = pm.newQuery(Person.class, "age > 25");
query.setOrdering("age ascending");
Collection results = (Collection)query.execute();
System.out.println( "Over-24 ordered:");
Iterator it = results.iterator();
while(it.hasNext()){
Person p = (Person) it.next();
System.out.println( p.toString());
}
query.closeAll();
}


    The parameterPassing method shows how to use a dynamic parameter to retrieve instances of a class:

//retrieve a person according to his name
public static void parameterPassing(PersistenceManager pm){
Query query = pm.newQuery(Person.class, "name == myName");
query.declareParameters("String myName");
String sName = "Labbe Loic";
Collection results = (Collection)query.execute(sName);
System.out.println( sName + " has been retrieved:");
Iterator it = results.iterator();
while(it.hasNext()){
Person p = (Person) it.next();
System.out.println( p.toString());
}
query.closeAll();
}


    The compositeFilter method shows how to specify a composite filter such as a or logic condition:

//retrieve a person according to his name and persons according to their age
public static void compositeFilter(PersistenceManager pm){
Query query = pm.newQuery(Person.class);
query.declareParameters("String myName");
query.setFilter("(name == myName) || (age > 45)");
Collection results = (Collection)query.execute("Labbe Loic");
System.out.println( "Result of (name=Labbe Loic || age > 45):");
Iterator it = results.iterator();
while(it.hasNext()){
Person p = (Person) it.next();
System.out.println( p.toString());
}
query.closeAll();
}

    The navigationSingleField method shows how to navigate through the object graph to define the filter:

//retrieve a person according to his contact details
public static void navigationSingleField(PersistenceManager pm){
Query query = pm.newQuery(Person.class);
query.declareParameters("String phoneNumber");
query.setFilter("contactDetails.phone == phoneNumber");
Collection results = (Collection)query.execute("1234567890");
System.out.println( "Result of (contatcDetails.phone == 1234567890):");
Iterator it = results.iterator();
while(it.hasNext()){
Person p = (Person) it.next();
System.out.println( p.toString());
}
query.closeAll();
}

    The navigationMultiValuedField method shows how to navigate through a collection to define the filter:

//retrieve a person according to the age of his children 
public static void navigationMultiValuedField(PersistenceManager pm){
Query query = pm.newQuery(Person.class);
query.declareVariables("Person child");
query.setFilter("children.contains(child) & child.age < 5");
Collection results = (Collection)query.execute();
System.out.println( "Person(s) having children under-5:");
Iterator it = results.iterator();
while(it.hasNext()){
Person p = (Person) it.next();
System.out.println( p.toString());
}
query.closeAll();
}

   
    To launch the step 4:
    You can view the results of the queries method in your database via the DatabaseManager (see Tutorial Environment): table T_ADDITIONAL_PERSON
    The output result should be:
   
[java] All Person instances:
[java] Bordes Raymond, age=75, children=[], contact details=[email=raymond.bordes@wanadoo.fr, phone=1234567890]
[java] Couture Zelie, age=23, children=[Landreau Vincent], contact details=[email=zelie.couture@wanadoo.fr, phone=0987654321]
[java] Grange Jean-Luc, age=54, children=[Couture Zelie, Lambert Celine], contact details=[email=jeanluc.grange@wanadoo.fr, phone=1234567890]
[java] Labbe Loic, age=16, children=[], contact details=[email=loic.labbe@wanadoo.fr, phone=1234567890]
[java] Lambert Celine, age=19, children=[], contact details=[email=celine.lambert@wanadoo.fr, phone=0987654321]
[java] Landreau Vincent, age=2, children=[], contact details=[email=vincent.landreau@wanadoo.fr, phone=0987654321]

[java] Young persons (<20 years old) :
[java] Labbe Loic, age=16, children=[], contact details=[email=loic.labbe@wanadoo.fr, phone=1234567890]
[java] Lambert Celine, age=19, children=[], contact details=[email=celine.lambert@wanadoo.fr, phone=0987654321]
[java] Landreau Vincent, age=2, children=[], contact details=[email=vincent.landreau@wanadoo.fr, phone=0987654321]

[java] Over-24 ordered:
[java] Grange Jean-Luc, age=54, children=[Couture Zelie, Lambert Celine], contact details=[email=jeanluc.grange@wanadoo.fr, phone=1234567890]
[java] Bordes Raymond, age=75, children=[], contact details=[email=raymond.bordes@wanadoo.fr, phone=1234567890]

[java] Labbe Loic has been retrieved:
[java] Labbe Loic, age=16, children=[], contact details=[email=loic.labbe@wanadoo.fr, phone=1234567890]

[java] Result of (name=Labbe Loic || age > 45):
[java] Bordes Raymond, age=75, children=[], contact details=[email=raymond.bordes@wanadoo.fr, phone=1234567890]
[java] Grange Jean-Luc, age=54, children=[Couture Zelie, Lambert Celine], contact details=[email=jeanluc.grange@wanadoo.fr, phone=1234567890]
[java] Labbe Loic, age=16, children=[], contact details=[email=loic.labbe@wanadoo.fr, phone=1234567890]

[java] Result of (contatcDetails.phone == 1234567890):
[java] Bordes Raymond, age=75, children=[], contact details=[email=raymond.bordes@wanadoo.fr, phone=1234567890]
[java] Grange Jean-Luc, age=54, children=[Couture Zelie, Lambert Celine], contact details=[email=jeanluc.grange@wanadoo.fr, phone=1234567890]
[java] Labbe Loic, age=16, children=[], contact details=[email=loic.labbe@wanadoo.fr, phone=1234567890]

[java] Person(s) having children under-5:
[java] Couture Zelie, age=23, children=[Landreau Vincent], contact details=[email=zelie.couture@wanadoo.fr, phone=0987654321]
    Top


Object model

    The step 5 deals with inheritance. To illustrate jdo inheritance support, we will work on the following object model:
   

An Employee is identified by his name and his type. We use an horizontal  mapping to define the inheritance relationship between objects (Speedo Inheritance support manual for more info): that is the reason why the PK is composite, the type field being the filter of the Employee, Manager and Worker classes.

A Manager is an employee with a team and supervises many workers.
A Worker is an employee with a partTime field and is supervised by many managers (M-N relationship).

The source code of the java classes is located in the org.objectweb.speedo.tutorial.pobjects.additional.inheritance package.


The inheritance.jdo file is as follows (see comments in red for inheritance specific tags):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" "jdo.dtd">
<jdo>
<package name="org.objectweb.speedo.tutorial.pobjects.additional.inheritance">

<class name="Employee" identity-type="application" objectid-class="org.objectweb.speedo.tutorial.pobjects.additional.inheritance.EmployeeId"> 1
<extension vendor-name="speedo" key="sql-name" value="T_ADDITIONAL_EMPLOYEE"/>
<!-- the inheritance filter : the "type" field-->
<extension vendor-name="speedo" key="inheritance-filter" value="type"/>
<!-- the value of the filter for the Employee class: "employee" -->
<extension vendor-name="speedo" key="inheritance-key" value="employee"/>
<field name="name" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="NAME"/>
</field>
<field name="type" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="TYPE"/>
</field>
<field name="age">
<extension vendor-name="speedo" key="sql-name" value="AGE"/>
</field>
<field name="company">
<extension vendor-name="speedo" key="sql-name" value="COMPANY"/>
</field>
</class>

<!-- Manager extends Employee-->
<class name="Manager" persistence-capable-superclass="Employee">
<!-- the type of inheritance: "filtered"-->
<extension vendor-name="speedo" key="inheritance-mapping" value="filtered"/>
<!-- the value of the filter for the Manager class: "manager" -->
<extension vendor-name="speedo" key="inheritance-key" value="manager"/>
<field name="team">
<extension vendor-name="speedo" key="sql-name" value="TEAM"/>
</field>
<!-- M-N relationship -->
<field name="workers" persistence-modifier="persistent">
<collection element-type="Worker"/>
<extension vendor-name="speedo" key="join-table" value="MANAGER_TO_WORKER"/>
<extension vendor-name="speedo" key="source-foreign-keys" value="NAME=M_NAME,TYPE=M_TYPE"/> 2
<extension vendor-name="speedo" key="target-foreign-keys" value="NAME=W_NAME,TYPE=W_TYPE"/>
<extension vendor-name="speedo" key="reverse-field" value="managers"/>
</field>
</class>

<!-- Worker extends Employee-->
<class name="Worker" persistence-capable-superclass="Employee">
<extension vendor-name="speedo" key="inheritance-mapping" value="filtered"/>
<!-- the value of the filter for the Worker class: "worker"-->
<extension vendor-name="speedo" key="inheritance-key" value="worker"/>
<field name="partTime">
<extension vendor-name="speedo" key="sql-name" value="PART_TIME"/>
</field>
<field name="managers" persistence-modifier="persistent">
<collection element-type="Manager"/>
</field>
</class>

</package>
</jdo>


1
For the composite identifier of the Employee class, we defined an EmployeeId class. All fields of the object identifer class must be public and fields of the persistent class:

public class EmployeeId {

public String name;
public String type;

...
}


2 Note that for the M-N relationship between Worker and Manager, a join table has been defined with composite source and target foreign keys. Indeed the PK of the T_ADDITIONAL_EMPLOYEE table is composed of the NAME and TYPE fields. The ',' separator is used to define composite foreign keys:

<extension vendor-name="speedo" key="source-foreign-keys" value="PKField1=FKField1,PKField2=FKField2"/> 
     

    The results of the mapping on the database is as follows:


With the filtered mapping, the three classes EMPLOYEE, MANAGER & WORKER are mapped on the same table: T_ADDITIONAL_EMPLOYEE.












The join table of the M-N relationship is composed of four fields: the composite PK of the EMPLOYEE table for the Manager (M_NAME, M_TYPE) and the composite PK of the EMPLOYEE table for the Worker (W_NAME, W_TYPE)

Top



Step 5: inheritance

   In this step, we are going to make persistent objects belonging to an inheritance object graph described in the previous object model:
   
/**
* This steps describes how to:
* make persistent inherited objects
*/
public static void inheritance() {
System.out.println( "***************Inheritance*****************");
PersistenceManager pm = pmf.getPersistenceManager();
//create the employees, workers and managers
createInheritedObjects(pm);
//get all the employees
iterateExtent(pm, Employee.class);
//get all the workers
iterateExtent(pm, Worker.class);
//get all the managers
iterateExtent(pm, Manager.class);
pm.close();
}

/**
* Create persistent objects
*/
public static void createInheritedObjects(PersistenceManager pm){
//create employees
Employee employee1 = new Employee("Herve Landry", 42, "Tetra Pack");
Employee employee2 = new Employee("Vincent Racado", 30, "Tetra Pack");
//create workers
Worker worker1 = new Worker("Caroline Bret", 33, "Tetra Pack", true);
Worker worker2 = new Worker("Evelyne Jain", 54, "Tetra Pack", false);
Worker worker3 = new Worker("Tim Jorge", 28, "Tetra Pack", false);
//create managers
Manager manager1 = new Manager("Jean Duverge", 52, "Tetra Pack", "Sales");
Manager manager2 = new Manager("Eric Mento", 49, "Tetra Pack", "Marketing");

worker1.addManager(manager1);
worker2.addManager(manager1);
worker2.addManager(manager2);
worker3.addManager(manager2);

Collection employees = new ArrayList();
employees.add(employee1);
employees.add(employee2);
employees.add(worker1);
employees.add(worker2);
employees.add(worker3);
employees.add(manager1);
employees.add(manager2);

//make persistent all the persons using a collection
pm.currentTransaction().begin();
pm.makePersistentAll(employees);
pm.currentTransaction().commit();
}

//iterate over all the instances of a class cl
public static void iterateExtent(PersistenceManager pm, Class cl){
Extent extent = pm.getExtent(cl, true);
Iterator it = extent.iterator();
System.out.println( "All " + cl.getName() + " instances:");
while(it.hasNext()){
Employee e = (Employee) it.next();
System.out.println( e.toString());
}
extent.close(it);
}
    To launch the step 5:
   You can view the results of the inheritance method in your database via the DatabaseManager (see Tutorial Environment): table T_ADDITIONAL_EMPLOYEE:



    Note that, iterating over all the Employee instances,  not only all the Employee instances but also all the Worker and Manager instances are selected.

    Top

Step BackFollowing step