Persistate

Synchronising with persistent storage

Hide Navigation Pane

Synchronising with persistent storage

Previous topic Next topic No directory for this topic  

Synchronising with persistent storage

Previous topic Next topic Topic directory requires JavaScript JavaScript is required for the print function Mail us feedback on this topic!  

When you manipulate persistent objects in memory, Persistate keeps track of new, modified and deleted objects, and changes to the linkages between objects.  At some point, the corresponding objects and linkages in persistent storage need to be synchronised within what you have done in memory.

By default, this happens at the end of operation executions.  In a Persistate application, the unit of processing is the execution of an operation.  You define the operations you want in your application by listing them in the definition file -see Operation and Operation Group Definition for details.

For each operation, Persistate generates a stub method to execute it, within a class named for the operation group containing the operation.  In our Library example application, here is the method generated for the receive books operation, within the Action class.

/// <summary>
/// Executes the Receive books operation in the 
/// Action group.
/// </summary>
/// <param name="execution">The operation Execution object created for the
/// execution of the Receive books operation.</param>
/// <returns>An ExecutionResult which should be set with the result
/// of the operation.</returns>
public static ExecutionResult ExecuteReceiveBooks(Execution execution)
{
   // TODO  Implement this operation;
   return new ExecutionResult(ResultAction.NoAction, "Operation is not implemented");
 
}

Committing changes

Note the return value above which is an ExecutionResult.  In the stub, this specifies NoAction, since the operation as it is does nothing.  To synchronise changes with persistent storage, you need to use the ResultAction value Commit.  There are utility fields in ExecutionResult which provide a basic result with each ResultAction value, so you could use one of these as follows.

// perform all the work to receive books
...
return ExecutionResult.CommitResult;

This performs the synchronisation to persistent storage.  This performed under control of a transaction.  If objects from more than one database were modified, or any distributed collections were involved, it will be a distributed transaction.  If you want to show a status message in the status bar, or popup an information box, you can do this by using one of the ExecutionResult constructors.  For example.

// perform all the work to receive books
...
return new ExecutionResult(ResultAction.Commit, "Message in popup box", 
   "Message in status bar", 100.0);

The last parameter is a percentage complete value which updates a progress bar in the status bar.  There are various other constructors available, which allow other options including returning a result object from the operation execution, providing a handler for database exceptions and provide a detail as well as a simple message.  See the API documentation for details.

Rolling back changes

If you decide in your program that the operation cannot complete normally, and you want to abort it, you can do this using a ResultAction of Rollback.  Usually you will want to provide a message to the user, as in the following.

// perform all the work to receive books
...
return new ExecutionResult(ResultAction.Rollback, "Error detected in operation");

When you specify a ResultAction of Rollback, then Persistate reverses any modifications you have made to persistent objects in memory.  This includes

Re-instating the original value of modified objects.  For objects in classes with the clone on mutate function (see Class Category Definition) then the object is returned to the original value which was cloned on the first property set or call to SetModified().  For other objects, the contents of the object is refreshed from persistent storage.

Caution

The clone is made using Object.MemberwiseClone which clones all fields.  However the restore from the clone uses Persistent.CopyFrom which copies only persistent members.  If you need to copy other fields that you declare in your class, you should override Persistent.CopyTransientFrom,  (which is called from CopyFrom) and copy these fields in there.

Replacing any objects that were removed from collections, both contained and associated.  For contained collections, this replaces any deleted objects.
Removing any objects that were added to collections, both contained and associated.  For contained collections, this removes any new objects that were created.

Note that since database synchronisation happens after you return from your operation execution method, this roll-back does not actually involve any rolling back of a database transaction, since none was ever started.

Other options

There are a number of other ResultAction values you can return in your ExecutionResult.  These are:

ResultAction.NoAction.  No synchronisation with persistent storage takes place.  If you have made any modifications to objects in memory, they are kept by Persistate, and a commit from any subsequent operation execution will synchronise them.  In general, you should use this only when you have made no changes.
ResultAction.Warning.  This is similar to ResultAction.NoAction, but any popup message is displayed as a warning, rather than as information.
ResultAction.CommitWarning.  This is similar to ResultAction.Commit, but any popup message is displayed as a warning, rather than as information.
ResultAction.Exception.  Use this to report an exception.  Usually you use this by creating an ExecutionResult with the one Exception parameter constructor.   This performs the same action as ResultAction.Rollback, using the exception detail for the messages reported.
ResultAction.ReExecute.  This causes the operation to be executed again.  This is used internally by Persistate in cases where a database update conflict was resolved.  Don't use it unless you know what you are doing.