Here, the database access is made via a generated SQL query
string. For the Jedi with the id of
1000 (which is Obi Wan), this last line
of code produces the following execution string and sends it to the
database (assuming we've changed the property alive to
true and forceRating to
6.0).

You'll notice that we are using a different method and a
different stored procedure to write the data. The resulting string
looks like this.

InsertJedi
@name='Mace Windu', @alive=0,
@force_rating=9.7, @age=40

What happened here? We'll assumed that the property
jediId is provided by the database when a new entry is
made. Actually, we've specified this when we used the
@ParameterAssociation with the property
isAutoIdentity=true in the Jedi class
definition above. Since the database will provide the bean with a
primary key, the parameter @jedi_id is omitted in the
call string.

There is a catch here. Since jediId is provided by
the database, this data must be returned from the stored procedure
InsertJedi. At the moment, the method
executeStringInsert returns a JDBC
ResultSet, which can be used to return either the ID
or the entire database row that was just inserted. This information
has to be handled manually, but Amber will soon provide helper
functionality to easily inject the new ID into the new object.

Dealing with strings being used for reading and
writing is questionable when the focus lies more on type safety
compared to transparency. Because of the conversion of the
parameters to strings, type information is lost. However, there is
one big advantage with this technique: any query string can be
logged and given to database administrators for analysis in case
anything goes wrong, or simply when there is a question on what
exactly the application called or queried the database with. This
sort of transparency makes debugging easier.

If the list of fighters of the Jedi has been
altered, this has to be written manually into the database as well.
Depending on what happened to the Fighter list, the
crude way might be to delete all of the fighters of the
Jedi first, and then write the new list back into the
database. Assuming we have the object jedi at hand
and a list of new Fighter objects in our collection of
fighters, the following takes care of writing the new
list into the database. Further, we assume that a new
Fighter object is written into the database via the
stored procedure InsertFighter.

This code produces a set of execution strings like this, where
the name in each item is the value of the fighter item in the
collection fighters:

InsertFighter @jediId=..., @name="...";

You may have noticed that this approach is not wrapped in a
transaction. As mentioned above, there is no exception handling
implemented, so if the delete command fails, an
SQLException is raised and the subsequent for loop is
not executed. But what about the other case, when the following
InsertFighter call is going wrong? In a situation
where it is necessary to provide a transaction, it is best to code
this within the stored procedure that you are calling. If I wanted
to handle this within a transaction, what I'd do is code an update
stored procedure that takes all parameters from the
Fighter object plus the Jedi ID and
handles "new" fighters within. This topic might be worth discussing
in another article.