Package com.smartgwt.client.docs

# Interface TransactionChaining

public interface TransactionChaining

### Transaction Chaining

Transaction Chaining allows `queues` of `DSRequest`s to be "chained" together, such that later `DSRequests` in the queue can use the results of previous requests in the queue. This allows you to declaratively handle various situations where information only becomes available during the processing of a queue.

To see an example of server-driven transaction chaining used to commit a mixed transaction of an `Order` and related `OrderItem`s, see the Master/Detail Add sample.

Transaction Chaining is only available with Power Edition licenses or better. See the Editions & Pricing page for details.

As an example of Transaction Chaining, consider an application that needs to do a master-detail add, which involves saving a new Record representing a sales order to an `order` DataSource, and also saving several related Records representing individual items in the order to an `orderItem` DataSource. The Records for the individual `orderItem`s need to set up foreign keys referencing the primary key assigned to the Record for the `order`, but the primary key of the `order` record is assigned only when the Record is inserted into the database; it cannot be known up-front.

You could resolve this programmatically - for example, you could use DMIs to store and retrieve the PK value using `servletRequest` attributes - but Transaction Chaining gives you an elegant, declarative, code-free alternative, giving you a way to declare that the foreignKey value for the `orderItem` records should use the primary key value resulting from the creation of the `order` record earlier in the same queue.

As another example, consider an application that allows a user to submit a free-form question which must be persisted to the database like a normal update, but which should initially show the user a list of previously-provided answers that appear to be relevant. The operation that handles the add of the question categorizes it by analyzing the text, and the category is added to the record inserted into the database, and thus to the record returned in the response. Now, via transaction chaining, a "fetch" operation later in the queue can pick up the newly assigned category and use it in criteria to fetch the list of related answers.

Transaction Chaining is implemented by specifying `DSRequestModifier`s in `OperationBinding.values` and `OperationBinding.criteria`. These two properties provide a general means of declaratively modifying DSRequests server-side, and transaction chaining is only one of their uses. They can also be used, for example, to implement security rules, by adding the currently-authorized user to the criteria of all fetch requests.

Specifically for transaction chaining, you specify `criteria` and/or `values` entries on the `operationBinding` where the `value` property references the $responseData Velocity context variable - see the "value" link for more details. Alternatively, you can use the `RPCManager` APIs `getFirstResponse()` and `getLastResponse()` to get access to the same information, either programmatically from DMI or custom DataSource Java code, or in `JSR 223 scripts`, or in Velocity expressions via the $rpc context variable.

### Client-driven Transaction Chaining

A limited form of transaction chaining (limited for security reasons) is possible without server-side operationBinding configuration, using `fieldValueExpressions`. The primary intended use case is a master-detail add, where the detail records require the master's primary key for use as foreign keys, but that value is not known until the master record has been inserted. In such a case, you create a `queue` of requests, with the add of the master record first, followed by the detail records, each of which has `fieldValueExpressions` set up to use `$masterId` like so:

          DSRequest properties = new DSRequest();
          Map fve = new HashMap();
          fve.put("fkField", "$masterId");
          properties.setFieldValueExpressions(fve);
          myDataSource.addData(record, callback, properties);

It is also possible to achieve the same thing in a less compact but more flexible way by using the `$responseData` context variable (note that client-driven usages of `$responseData` are limited for security reasons - see `fieldValueExpressions` for details). This approach allows you to reference values where there is no declared foreignKey relationship, and it allows you to reference responses other than the most recent one. For example:

          DSRequest properties = new DSRequest();
          Map fve = new HashMap();
          fve.put("anyField", "$responseData.first.anyOtherField");
          properties.setFieldValueExpressions(fve);
          myDataSource.addData(record, callback, properties);

To see an example of client-driven transaction chaining used to commit a mixed transaction of an `Order` and related `OrderItem`s, see the Master/Detail Add sample.

As with Server-Side Transaction Chaining, `fieldValueExpressions` can be used to affect `dsRequest.criteria` as well. For example, perhaps you are fetching the most recent Order and its related OrderItems, by sorting the returned Orders by `orderDate` and asking for only one record. Since you are fetching the most recent Order, you don't have the Order.orderId value available to fetch related OrderItems by passing the `Order.orderId` value as criteria for `OrderItem.orderId`. You need the `primaryKey` of whichever Order turns out to be most recent. Use `fieldValueExpressions` like so to solve this case:

           RPCManager.startQueue();
           DSRequest orderRequestProperties = new DSRequest(DSOperationType.FETCH);
           orderRequestProperties.setStartRow(0);
           orderRequestProperties.setEndRow(1);
           orderRequestProperties.setSortBy(new SortSpecifier("orderDate", SortDirection.DESCENDING));

           DataSource.get("Order").fetchData(null, null, orderRequestProperties);

           DSRequest orderItemRequestProperties = new DSRequest(DSOperationType.FETCH);
           orderItemRequestProperties.setFieldValueExpressions(new HashMap<String, String>() {{
               put("orderId", "$responseData.first.orderId");
           }});

           DataSource.get("OrderItem").fetchData(null, null, orderItemRequestProperties);

           RPCManager.sendQueue();

### Stand-alone Application Transaction Chaining

Transaction chaining is supported when using transactions standalone. Every request within the same transaction will be eligible during the chaining. It works in the same way as it would if your application was a full blown Smart GWT application. See `Standalone DataSource Usage` for examples on how to do this.

See Also:
  - `DSRequestModifier`
  - `DSRequest.getFieldValueExpressions()`
  - `DSRequestModifier.value`
  - `DSRequestModifier.start`
  - `DSRequestModifier.end`
  - `OperationBinding.criteria`
  - `OperationBinding.values`