Title: DataObject State Management
Arguably the second most important function of DataContext (first is performing queries) is keeping track of changes made to the registered DataObjects. "Registered" is a keyword here - registering an object with DataContext is what gives this object its persistent qualities.
Behind the scenes "registering an object" results in storing this object in a map using its ObjectId as a key, setting "dataContext" property of a DataObject to the current DataContext, and taking a snapshot of all persistent properties to be able to track later modifications. Objects can become "registered" in two ways:
Whenever a selecting query is executed by a DataContext, all fetched objects are automatically registered with this DataContext. On the other hand, newly created objects must be registered explicitly:
import org.apache.cayenne.access.DataContext; ... DataContext context; // assume this exists Artist artist = new Artist(); context.registerNewObject(artist); // after the line above is executed, artist object acquired "persistent" behavior // and is said to be "managed" by DataContext
This code can be simplified - object creation and registrations steps can be combined in one method call:
import org.apache.cayenne.access.DataContext; ... DataContext context; // assume this exists Artist artist = (Artist) context.newObject(Artist.class);
This method relies on the presence of a no-argument constructor in the DataObject class.
State transitions of DataObjects from persistence point of view are discussed in the "Design" chapter. State of each individual object is described by an integer constant obtained via a call to DataObject.getPeristenceState(). Allowed states are defined as static variables in PersistenceState class.
When a new object is inserted to the DataContext as described above, it becomes "NEW":
import org.apache.cayenne.access.DataContext; ... DataContext context; // assume this exists // artist will become PersistenceState.NEW Artist artist = (Artist) context.newObject(Artist.class);
When a DataContext is committed, such object becomes "COMMITTED":
// artist will become PersistenceState.COMMITTED
context.commitChanges();
When any of the attributes or relationships of the fetched or committed object are changed, such an object becomes MODIFIED:
// this will change the object state to PersistenceState.MODIFIED artist.setName("NewName");
When a fetched or committed object is explicitly deleted from the DataContext, object becomes DELETED:
// this will change the object state to PersistenceState.DELETED
context.deleteObject(artist);
DataContext is said to have changes if it has one or more registered objects in a state PersistenceState.MODIFIED, PersistenceState.NEW or PersistenceState.DELETED. DataContext provides the following method to check if it has any changed objects:
There is also a way to obtain a list of changed objects in each one of the above states:
All of the uncommitted objects ("uncommitted" means "new", "modified" or "deleted") are saved ("committed") to the database with a single method call on the DataContext:
Method commitChanges takes care of building correct SQL statements, generating primary keys and transactional behaviour. It roughly follows this scenario:
There is a way for the DataContext to undo all uncommitted changes:
This will restore the persistence state and the values of all registered objects to the values that objects had when they were fetched or the last commitChanges was executed. This effectively restores previously committed state of the object graph. Note that any NEW objects are unregistered from the context.