Guide  Reference  Contents  Previous  Next  Index
Objectivity/DB provides a variety of mechanisms for retrieving objects from a federated database. You can retrieve individual objects based on their application-defined names and links with other objects. In addition, you can search storage objects for objects of a given class, possibly restricting the search based on the values of certain persistent fields. Finally, you can traverse the entire storage hierarchy, retrieving all objects within each storage object.
The following general guidelines apply to retrieval methods.
The return type of every retrieval method is Object; you should cast the retrieved object to the appropriate class before using it.
The most direct way to retrieve an object is to look it up by name. Of course, this assumes that the object has been given a name, as described in Chapter 10, "Naming Persistent Objects".
To retrieve an object with a particular root name, call the lookup method of the federated database or database in which it is a named root. The session that owns the local representation of the federated database or database must be in a transaction.
The lookup method takes the root name as its parameter and returns the object with that root name. The session must be able to obtain a read lock on the root dictionary of the federated database or database. The lookup method throws a checked exception (ObjectNameNotFoundException) if there is no object with the specified name.
ExampleThis code fragment retrieves an object of the Salesperson class by looking up its root name in the database salesDB. The complete method definition appears in the Sales.Interact programming example . The Interact class has a static field called session, which is initialized to contain an instance of the Session class when the connection is opened; all examples in this chapter use session for transaction control.
// Static utility to retrieve a salesperson public static Salesperson lookupSalesperson (...) { Salesperson salesperson; ... session.begin(); ... ooDBObj salesDB = ...; ... String rootname = String.valueOf(employeeID); // Look up the salesperson try { salesperson = (Salesperson) salesDB.lookup(rootname); } catch (ObjectNameNotFoundException e) { System.out.println("No salesperson with Employee ID " + rootname); session.abort(); return null; } session.commit(); ... }
To look up an object by its scope name, call the lookupObj method of the scope object. The session that owns the local representation of the scope object must be in a transaction.
The lookupObj method takes the scope name as its parameter and returns the object with that scope name. The session must be able to obtain a read lock on the scope object's name map. A runtime error is thrown if lookupObj fails to find the object; for example, because there is no object with the specified name, a runtime error is thrown.
ExampleThis code fragment retrieves an object of the Contact class by looking up its name in the scope of the container scope. The complete method definition appears in the Sales.Interact programming example .
// Static utility to retrieve a contact public static Contact lookupContact (...) { Contact contact; ... session.begin(); ... String scopename = ...; ooContObj scope = ...; try { contact = (Contact) scope.lookupObj(scopename); } catch (ObjyRuntimeException e) { System.out.println("No contact named " + scopename); session.abort(); return null; } ... session.commit(); ... }
To look up an object by its name in an application-defined dictionary:
The session must be able to obtain a read lock on the name map.
The lookup method takes the name as its parameter and returns the object in the name map whose key is the specified name. You should call lookup only if isMember returns true; lookup throws an ObjyRuntimeException if you try to look up a name that does not exist in the name map.
ExampleThis code fragment retrieves an object of the Client class by looking up its name in the application-defined dictionary represented by the name map nameTable. The complete method definition appears in the Sales.Interact programming example .
// Static utility to retrieve a client public static Client lookupClient (String companyName) { ooMap nameTable; ... session.begin(); ... nameTable = ...; // Look up name in table ... if (nameTable.isMember(companyName)) { Client client = (Client)nameTable.lookup(companyName); session.commit(); return client; } else { System.out.println("No client named " + companyName); session.abort(); return null; } }
An object graph is a group of related persistent objects that are linked together in a directed graph data structure. Each link in the graph can be a persistent field that references another object or a relationship. Once you have retrieved one object in the graph (for example, a named root), you can follow links to retrieve the other objects in the graph.
When you fetch a retrieved object's data, you retrieve any objects the retrieved object references in its persistent fields. Note however, that the referenced objects are empty; you should fetch their persistent data before you access their persistent fields.
If you define field access methods for every class whose objects are included in an object graph, the process of fetching persistent data and retrieving referenced objects is completely transparent. The access methods that get the values of persistent fields also fetch the data for you, retrieving any referenced objects after obtaining the necessary locks. Remember that you should call a persistent object's field access methods only when the session that owns the object is in a transaction.
ExampleThis code fragment first retrieves an object of the Client class; the lookupClient method starts its own transaction, so that method is called outside a transaction. Once the client is retrieved, a call to its getSalesRep field access method gets the client's sales representative, an object of the Salesperson class. When getSalesRep (shown at the end of the example) calls fetch, the client's data (including the empty salesperson object) is retrieved from the database. The complete printClientRepresentative method definition appears in the Sales.Interact programming example .
// Static utility to print the name of a client company's // sales representative public static void printClientRepresentative(String companyName) { ... Client client = Interact.lookupClient(companyName); ... session.begin(); // Get the client's sales representative Salesperson salesPerson = client.getSalesRep(); ... session.commit();
public Salesperson getSalesRep() { fetch(); return this.salesRep; }
If a persistent field contains a persistent collection rather than a scalar persistent object, you can retrieve the elements of the collection as described in "Retrieving Elements of a Persistent Collection".
After you retrieve an object, you must fetch its persistent data to read its relationship field into memory. If you try to access the object's relationship field before you have fetched its data, a NullPointerException is thrown.
If you define relationship access methods for each relationship, the process of fetching persistent data and retrieving related objects is completely transparent. The access method for a relationship fetches the object's data, retrieves the related object, and casts the related object to the correct class. Remember that you should call a persistent object's relationship access methods only when the session that owns the object is in a transaction.
You can retrieve an object related by a to-one relationship by calling that relationship's get method. The get method takes no parameters and returns the related object, or null if there is no related object.
ExampleThis code fragment first retrieves an object of the Contact class; the lookupContact method starts its own transaction, so that method is called outside a transaction. Once the contact is retrieved, a call to its getSalesperson relationship access method gets the contact's salesperson, an object of the Salesperson class. When getSalesperson (shown at the end of the example) calls fetch, the contact's data, including its salesperson relationship, is retrieved from the database. The complete printSalespersonForContact method definition appears in the Sales.Interact programming example .
// Static utility to print the name of a contact's salesperson public static void printSalespersonForContact (...) { Contact contact = Interact.lookupContact(...); ... session.begin(); // Get the contact's salesperson Salesperson salesPerson = contact.getSalesperson(); ... session.commit();
public Salesperson getSalesperson() { fetch(); // Cast retrieved object to class Salesperson return (Salesperson)this.salesperson.get(); }
You can retrieve objects related by a to-many relationship by calling that relationship's scan method. The scan methods return an iterator initialized to find the related objects.
When you want to retrieve all related objects, you should call the relationship's scan method with no parameters. The scan method returns an iterator that finds all related objects.
ExampleThis code fragment first retrieves an object of the Salesperson class; the lookupSalesperson method starts its own transaction, so that method is called outside a transaction. Once the salesperson is retrieved, a call to its getAllContacts relationship access method (shown at the end of the example) gets an iterator that finds all contacts for the salesperson. The iterator is used to retrieve each of the salesperson's contacts, which are objects of the Contact class. The complete printContactsForSalesperson method definition appears in the Sales.Interact programming example.
// Static utility to print the names of a salesperson's contacts public static void printContactsForSalesperson(int employeeID) { ... Salesperson salesperson = Interact.lookupSalesperson(employeeID); ... session.begin(); // Get the salesperson's contacts Iterator itr = salesperson.getAllContacts(); ... Contact contact; while (itr.hasNext()) { contact = (Contact)itr.next(); // Cast to Contact contact.printName(); } session.commit();
public Iterator getAllContacts () { fetch(); return this.contacts.scan(); }
When you want to retrieve only those related objects that satisfy some condition, you should call the relationship's scan method, passing the condition as a parameter. The condition is a predicate in the Objectivity/DB predicate query language. The scan method returns an iterator that finds those related objects satisfying the specified condition.
ExampleIn this example, the findContact relationship access method of the Salesperson class retrieves a particular related contact of a salesperson; the findContactsByCompany access method returns an iterator that finds the related contacts in the specified company.
// Relationship access methods ... public Contact findContact(String firstName, String lastName, String company) { fetch(); String predicate = new String("company == \"\"" + company + "\" and " + "lastName == \"\"" + lastName + "\" and " + "firstName == \"\"" + firstName + "\""); Iterator itr = this.contacts.scan(predicate); if (itr.hasNext()) return (Contact)itr.next(); // Cast to Contact else return null;
public Iterator findContactsByCompany(String company) { fetch(); String predicate = new String("company == \"\"" + company + "\""); return this.contacts.scan(predicate); }
Once you have retrieved a persistent collection, you can call its methods to retrieve the elements it contains. Different methods are available for different kinds of collections.
Lists, unordered sets, and sorted sets are collections of persistent objects. You can iterate through such a collection, retrieving each object it contains. If the collection is ordered, you can additionally retrieve the element at a particular position within the collection.
You can call the iterator method of a collection of objects to obtain an iterator for finding all elements of the collection. For loop control, you call the iterator's hasNext method to test whether additional elements remain. Within the loop, you make successive calls to the iterator's next method to get a local representation of each object in the collection.
You can call the listIterator methods of a list to obtain a list iterator for finding its elements. One version of listIterator returns a list iterator initialized to start at the first element; the other version returns a list iterator initialized to start at a specified index within the list. A list iterator is an instance of a class that implements the java.util.ListIterator interface. In addition to the standard iterator methods, a list iterator has additional methods that allow you to reverse the direction of iteration:
Ordered collections of objects (lists and sorted sets) have methods to retrieve particular elements, identified by their position in the list.
Name maps, unordered object maps, and sorted object maps are collections of key-value pairs. You can retrieve the keys and values from such a collection.
You can iterate through a collection of key-value pairs, getting each key it contains. If the collection is ordered, you can additionally retrieve the key at a particular position within the collection.
To obtain an iterator for finding all the keys of a collection of key-value pairs:
You call the iterator's next method repeatedly to get each key in the collection. In the case of a name map, next simply returns the key string; in the case of an object map, next gets a local representation of the key object.
Sorted object maps have methods to retrieve particular keys, identified by their position in the list.
You can obtain values from a collection of key-value pairs in either of two ways. First, you can iterate through a collection of key-value pairs, retrieving each value it contains. Second, if you have already obtained a key from the collection, you can retrieve the value associated with that key.
To obtain an iterator for finding all the values of a collection of key-value pairs:
You call the iterator's next method repeatedly to get a local representation of each value in the collection.
Once you have obtained a key from a collection of key-value pairs, you can retrieve the object that is the value associated with that key. In the case of a name map, the key is a name. Retrieving the associated value is equivalent to looking up the object by name; see "Name in an Application-Defined Dictionary".
In the case of an object map, the key is another persistent object. You call the object map's get method, passing the key as the parameter.
The get method returns null if the collection does not contain an element with the specified key. To distinguish that situation from the situation in which the collection contains an element with the specified key and a null value, call the containsKey method; the parameter to containsKey is the key.
You can scan any storage object to find its contained objects of a particular persistence-capable class. In particular, you can:
If you need to find all containers in a database, you should use the contains method, which performs this operation more quickly than the scan method. See "Traversing the Storage Hierarchy".
To scan a particular storage object, call its scan method. Different versions of the scan method allow you to scan for all objects of the specified class or to scan for those objects of the class that satisfy a condition. In either case, the scan method returns an iterator initialized to find the specified objects.
When you want to retrieve all objects of a given class in a storage object, you should call the storage object's scan method, passing the package-qualified name of the class as the parameter. The session that owns the local representation of the storage object must be in a transaction.
ExampleThis code fragment retrieves all objects of the Salesperson class from the database salesDB. The complete method definition appears in the Sales.Interact programming example .
// Static utility to print the names of all salespeople public static void printAllSalesPeople() { ... session.begin(); // Get sales database ooDBObj salesDB = ...; Iterator itr = salesDB.scan("Sales.Salesperson"); Salesperson salesperson; while (itr.hasNext()) { // Cast to Salesperson salesperson = (Salesperson)itr.next(); salesperson.printName(); } session.commit(); }
When you want to retrieve only those objects of a class that satisfy some condition, you should pass both the package-qualified class name and the condition as parameters to the storage object's scan method. The session that owns the local representation of the storage object must be in a transaction.
The condition is a predicate in the Objectivity/DB predicate query language. The scan method returns an iterator that finds objects of the specified class that satisfy the specified condition. You can make a predicate scan more efficient by defining an index whose key fields are the fields you use in the predicate.
ExampleThis code fragment scans a container for clients (of the Client class) located in the specified state. The complete method definition appears in the Sales.Interact programming example .
// Static utility to print the clients in the specified state public static void printClientsInState(String state) { ... session.begin(); ooContObj clientCont = ...; String predicate = new String("state == \"\"" + state + "\""); Iterator itr = clientCont.scan("Sales.Client", predicate); Client client; while (itr.hasNext()) { client = (Client)itr.next(); // Cast to Client System.out.println(client.getCompanyName()); } session.commit }
Each class of storage objects has a method that allows you to get all contained objects. The session that owns the storage object must be in a transaction when you call one of these methods.
All these methods return an iterator initialized to find the objects contained in the storage object.
ExampleThis code fragment illustrates how to traverse the storage hierarchy of a federated database. The complete method definition appears in the Traversal.Tester programming example .
public static void traverse(ooFDObj fd) { ooDBObj db; ooContObj cont; ooObj basicObject; Iterator dbItr, contItr, objItr; session.begin(); // Get all databases dbItr = fd.containedDBs(); while (dbItr.hasNext()) { db = (ooDBObj)dbItr.next(); //Cast to ooDBObj // Get all containers in current database ... contItr = db.contains(); while (contItr.hasNext()) { // Cast to ooContObj cont = (ooContObj)contItr.next(); ... // Get all objects in current container objItr = cont.contains(); while (objItr.hasNext()) { // Cast to ooObj basicObject = (ooObj)objItr.next(); ... } } } session.commit(); }
Objectivity/DB identifies each persistent object in a federated database by a unique object identifier (OID). Although OIDs are internal identifiers that application programs usually don't use, the interface allows you to obtain the OID of an object and to retrieve an object by its OID.
To look up an object by its OID, call the objectFrom method of the federated database. The session that owns the local representation of the federated database must be in a transaction. You can specify the OID to be looked up either as an ooId object or as a string. The objectFrom method allows you to retrieve storage objects (databases and containers) as well as persistent objects.
You might specify the OID as an ooId if one session has a local representation of the object and you want another session to get a local representation of the same object. When the first session is in a transaction, you could call the getOid method of the object to obtain an ooId representing that object's OID. When the second session is in a transaction, you could pass the ooId as a parameter to the objectFrom method of the second session's federated database; the objectFrom method would create a local representation of the object belonging to the second session.
ExampleThis code fragment creates a new session and retrieves an object with the specified OID; the retrieved object belongs to the new session. The complete method definition appears in the Traversal.Tester programming example .
// Static utility to retrieve an object by its OID public static void retrieveAgain(ooId oid) { Session session = new Session(); ooFDObj fd = session.getFD(); ... // Get new local representation of object with specified OID session.begin(); ooObj myBasicObject = (ooObj)fd.objectFrom(oid); ... session.commit(); }
Guide  Reference  Contents  Previous  Next  Index