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
componentautoCommit
property to false to allow only manual calls to thecommit()
method. It is important to setautoCommit
tofalse
when you are going to make more than one change…so that theDataService
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