Once you have accessed some instances by iterating an Extent or executing a query, you can access related instances by traversing references and iterating through collections contained in the accessed instances. The JDO implementation ensures that the related objects are instantiated and read from the datastore. All classes that can access a fieldbased on its access modifier (public, private, etc.)can directly access and modify the field, just as they would if the application were not running in a JDO environment.
The following program accesses a specific Movie instance and determines how many DVD copies of the Movie are currently available for rent. It accesses a specific Movie instance and then navigates to related instances. Line [1] accesses the Movie, based on its title. Appendix E contains the implementation of the StoreQueries class. Line [2] accesses the set of associated MediaItem instances. We access each MediaItem instance on line [3] and determine if it is a DVD format on line [4]. If so, line [5] accesses its set of associated RentalItem instances. We acquire a reference to each RentalItem instance on line [6]. On line [7], we determine whether the RentalItem is currently being rented. If it is currently rented to a customer, the value of rental will not be null. If rental is null, then it should be in stock and available for rent. In this case, we increment the dvdRentalsInStock counter. Once all the instances have been accessed, we print the value of dvdRentalsInStock on line [8].
package com.mediamania.store; import java.util.Iterator; import java.util.Set; import javax.jdo.PersistenceManager; import javax.jdo.Extent; import com.mediamania.MediaManiaApp; import com.mediamania.content.Movie; public class DVDMovieInStock extends MediaManiaApp { private String title; public DVDMovieInStock(String title) { this.title = title; } public static void main(String[] args) { DVDMovieInStock inStock = new DVDMovieInStock(args[0]); inStock.executeTransaction( ); } public void execute( ) { int dvdRentalsInStock = 0; Movie movie = StoreQueries.getMovieByTitle(pm, title); [1] Set items = movie.getMediaItems( ); [2] Iterator iter = items.iterator( ); while (iter.hasNext( )) { MediaItem item = (MediaItem) iter.next( ); [3] if (item.getFormat( ).equals("DVD")) { [4] Set rentals = item.getRentalItems( ); [5] Iterator rentalIter = rentals.iterator( ); while (rentalIter.hasNext( )) { RentalItem rentalItem = (RentalItem) rentalIter.next( ); [6] Rental rental = rentalItem.getCurrentRental( ); if (rental == null) dvdRentalsInStock++; [7] } } } System.out.print(dvdRentalsInStock); [8] System.out.print(" DVD copies of the movie "); System.out.print(title); System.out.println(" are in stock"); } }
When you modify the field of a persistent instance, the instance is automatically marked as modified. When you commit the transaction, all of the updates are propagated to the datastore.
The following method is defined in the MediaItem class. It is called whenever one or more copies of a particular item are sold to a customer. An application calls this method to update the count of the quantity in stock and the number of items sold year-to-date.
public void sold(int qty) { if (qty > quantityInStockForPurchase) { // report error } quantityInStockForPurchase -= qty; soldYTD += qty; }
These MediaItem field updates are propagated to the datastore at commit.
Instances are automatically marked as modified when a field is changed, except for array fields. An array is a Java system object, and there is no means to associate it with a particular persistent instance that should be notified when it is updated. Some implementations may be able to track changes to an array in the enhanced code of the persistent class. Furthermore, some may track changes to an array that is passed as a reference outside the owning class to another class that has not been enhanced. But these are advanced capabilities that most implementations cannot support, and they are not required by JDO. Thus, if you change an array field in a persistent instance, the changes might not be flushed to the datastore. If you would like your applications to be portable and work correctly across all JDO implementations, you should not depend on the automatic tracking of array changes.
You can call the following JDOHelper method to mark a specific field as being dirty (modified), so that its values are propagated to the datastore when the instance is flushed:
static void makeDirty(Object obj, String fieldName);
The fieldName parameter identifies the field to be marked as dirty; it can optionally include the field's fully qualified package and class name. This method has no effect if the obj parameter is transient, null, or not a persistent class, or if the field identified by fieldName is not a managed field.