Saturnboy
 2.19

Faking Transaction in LCDS 3

,

Alas, LCDS 3 doesn’t support the notion of transaction (in the sense of a Database Transaction). I assume that somewhere deep within the system transactions are used to ensure correctness of data in the db, but none of this is exposed to the user. Fortunately, it is possible to bundle up a bunch of updates on the client and push them all at once to the server. Fake transactions, as I like to call them, are quite useful. But they can also be dangerous because they are not really transactions (hence the fake part), and don’t always work as you would hope.

Fake It

Faking a tranaction is done using the autoCommit property on a generated service. According to the docs, setting autoCommit to false blocks Data Management from pushing any changes to the server until commit() is called manually.

Here’s a direct quote:

“…set a DataService component autoCommit property to false to allow only manual calls to the commit() method. It is important to set autoCommit to false when you are going to make more than one change…so that the DataService component can batch those changes and send them in one batch to the destination.”

So to make life easy, I made a simple static function that does the autoCommit gymnastics:

public static function fakeIt(service:DataService, func:Function):AsyncToken {
    if (!service.autoCommit) {
        throw new Error("ERROR: autoCommit is already off.");
    }
    if (service.commitRequired) {
        throw new Error("ERROR: another transaction is already open.");
    }
 
    service.autoCommit = false;
    func();
    var token:AsyncToken = service.commit();
    service.autoCommit = true;
    return token;
}

After some error handling, we toggle autoCommit to false, call our function, then commit any updates, toggle autoCommit back on, and return the token.

Usage

Using our fake transaction function is straight forward, and typically involves passing in and inline anonymous function.

Imagine our favorite example of teams and players, where each team has one-to-many players. We might choose to perform a sequence of operations to add a new player to an existing team, like this:

var token:AsyncToken = FakeTransaction.fakeIt(
    teamService.serviceControl,
    function ():void {
        //rename the team
        team.name = 'Denver Nuggetz';
 
        //create player
        var p:Player = new Player();
        p.name = 'Carmelo Anthony';
 
        //wire both side of relationship
        p.team = team;
        team.players.addItem(p);
 
        playerService.createPlayer(p);
    });
 
token.addResponder(new AsyncResponder(successHandler, faultHandler));

In this case, the fake transaction is used to ensure the team is renamed and the player is added. Both operations occur together, so it should not be possible to have the new player on the old team, or have the renamed team without the new player.

Warning! Danger!

Experience has shown me that fake transactions don’t always work as one would expect if they were real transactions. Sometimes, particularly when you are manipulating entities already under Data Management, it seems like operations are not really batched but instead executed one at a time. Thankfully, it appears that LCDS is order preserving, and by that I mean it doesn’t magically re-order things. LCDS always executes operations in the order they come in. I can only recommend you test your application vigorously to ensure what you expect to happen actually happens (FlexUnit4 is pretty awesome for testing async backends).

Files

Comments are closed

© 2017 saturnboy.com