Saving an object (simple inserts and updates)
To write an object into the database, call its save() method. Depending on whether the data object was newly created or was read from the database, the corresponding row in the database table is inserted or updated. If the object is new, its primary key(s) is/are generated automatically if the id method was set to "native" or "idbroker" in the schema.xml.
As an example, consider the following code, which creates an Author object and inserts it into the database.
Author stevens = new Author(); stevens.setFirstName("W."); stevens.setLastName("Stevens"); stevens.save();
If the generator properties "torque.complexObjectModel" and "torque.objectIsCaching" were not set to false at generation time, any objects which are referenced in the foreign key Lists of the object are also saved.
For example, in the following code, calling book.save() also saves the author added to the book:
Author bloch = new Author(); bloch.setFirstName("Joshua"); bloch.setLastName("Bloch"); Book effective = new Book(); effective.setTitle("Effective Java"); effective.setISBN("0-618-12902-2"); effective.setPublisher(addison); bloch.addBook(effective); bloch.save(); //also saves the book "effective"
Note that the save is only propagated in the 1->n directions of foreign
keys, not in the n->1 direction. I.e. in the above example, calling
effective.save()
would NOT save the corresponding author.
If the object which save method is called is neither new nor modified,
it is not saved. Internally, this is handled via the isNew
and modified
flags of the object.
There are alternative ways to insert or update an object in the database:
you can pass the objects to the doInsert()
or
doUpdate()
methods of their corresponding Peers, or you can
create a ColumnValues object which contains the data of the object
and pass the Criteria object to the doInsert()
or
doUpdate()
methods of the Peer class.
Note that if you construct a ColumnValues object for a new object,
the id field need not be added to the ColumnValues;
it is taken care of by Torque internally.
Linking objects
This section is about how to establish foreign-key relations between objects. As explained above, if the generator properties "torque.complexObjectModel" and "torque.objectIsCaching" were not set to false at generation time, collection fields will be created for each foreign key in the object which is referenced by the foreign key, and objects which are contained in such a collection will also be saved. On the other hand, if the referencing object is saved, the referenced object will not be saved. This default behavior can be overridden by overriding the save methods of the respective objects.
To make this more clear, let's consider an example where the table book
has a foreign key on the table author. This means, a book object
can reference an author object. In this case, Torque will generate
a collection of books in the author object which can be accessed by
the methods getBooks()
, addBook()
and isBooksInitialized()
.
The collection can contain the books referencing the author object.
Also, in the book object, there are methods getAuthor()
and setAuthor()
which can manipulate the referenced author.
In the case where we have a new author object, and we add a book object
to the referencing books via the author's addBook()
method
and then save the author object, the linked book object will be saved
as well.
On the other hand, if we have the same situation (a book added to an
author via the addBook()
method) and then save the book,
the referenced author will _NOT_ be saved.
This is because foreign keys often represent a logical tree structure:
A parent object (in our case author) has potentially many child objects
(in our case books). If a parent is saved, the children are also saved
by default, but not the other way round.
Bulk modifying linked objects
In the tutorial database, the book table has a foreign key to the author table. So as discussed above, the author object has a collection of books, and books added to this collection get saved when the corresponding author object is saved. However, this does not mean that the collection of books associated to that author is actually synced to the book collection in the author object. For example, if books are removed from the author's book collection and the author object is saved afterwards, the book is not deleted or unbound from the author, it is just disregarded in the save and the collection in the author object and the database are out of sync.
To provide am simple means of syncing the state of such a collection
to the database, Torque generates methods to set the state of linked
objects in an object and the database: the setAndSave methods.
For example, the AuthorPeer class has a method
setAndSaveBooks(Author toLinkTo, Collection<Book> toSave)
which does the following:
- The current collection of books which are linked to the author toLinkTo and which are also in the list toSave is read from the database into the list intersection.
- All books in toSave which are not in intersection are inserted.
- All books in intersection which are also in toSave are updated with the corresponding values in toSave and saved.
- All books in the database which are linked to the author but are not in toSave are deleted from the database.
After this procedure, the list of books which are linked to the passed author object in the database and the cached list of books in the passed author object are exactly the passed list of books. This is an easy way to specify the list of linked objects in the database; and it is better than just deleting and re-inserting the linked books because it preserves primary keys of existing objects and does not execute any database writes for unmodified objects.
Mass updates
If you want to update many objects at once, use the doUpdate(Criteria, ColumnValues) method in BasePeer. For example, to set the name attribute to null for all authors with an id greater than 5, use:
Criteria criteria = new Criteria(); criteria.where(AuthorPeer.AUTHOR_ID, 5, Criteria.GREATER_THAN); ColumnValues columnValues = new ColumnValues(); columnValues.put(AuthorPeer.NAME, new JdbcTypedValue( null, java.sql.Types.VARCHAR)); BasePeer.doUpdate(criteria, columnValues);
insert ... select ... statements
The supported Databases allow to insert values which are previously selected from the database, using an insert ... select ... statement. These statements can be created using a special doInsert method in the Peer classes: The first argument is an array of Column objects which define the columns where the data is inserted (all these columns must be in one table, though this is not checked by Torque), and the second argument is a Criteria which select the values to be inserted from the database (this criteria must select the same number of columns as are in the first array, although again this is not checked by Torque). As an example (which makes no sense in a logical sense), we can insert a number of authors into the author table, setting the name of the inserted authors to the title of all books in the database:
int numberOfInsertedRows = AuthorPeer.doInsert( new Column[] {AuthorPeer.NAME}, new Criteria().addSelectColumn(BookPeer.TITLE));
Deleting objects
If you want to delete an author which was already loaded into memory, then simply pass the object to the doDelete method of the peer:
AuthorPeer.doDelete(author);
You do not need to load authors to delete them, you can also use a Criteria object to perform deletes. For example, to delete the author with the id 3 without loading the author object, use:
Criteria criteria = new Criteria(); criteria.where(AuthorPeer.AUTHOR_ID, 3); AuthorPeer.doDelete(criteria);
The latter method can also be used for mass deletes. E.g. to delete all authors with an id greater than 5, use:
Criteria criteria = new Criteria(); criteria.where(AuthorPeer.AUTHOR_ID, 5, Criteria.GREATER_THAN); AuthorPeer.doDelete(criteria);
Default values
If a default is specified, the default value is used on both
a new java object and as column default value in the sql script
for the database.
However, when a java object is saved, the database value is always
overwritten because the normal behavior for saving a new object
is to write all fields.
This behavior can be overwritten by setting the column attribute
useDatabaseDefaultValue to true. In this case, the column is not
written on inserts if the value of the corresponding java field
is equal to the default.
It is a good idea to have a non-primary key field in each table where
useDatabaseDefaultValue is not set because otherwise you could run into
SQL syntax errors when an unchanged new object is changed
(because there are no values to insert).
One can use CURRENT_DATE, CURRENT_TIME and CURRENT_TIMESTAMP as default for Date fields. Setting the attribute useDatabaseDefaultValue to false or not setting it makes Torque use the current java time as initial field value when constructing the object and saving it to the database, not considering the database default. Setting the attribute useDatabaseDefaultValue to true makes Torque setting the initial field value to null and using the database default when the object is first saved to the database.