blog.jj5.net (2003 to 2005)

Commands, Transactions, etc.

Wed Mar 3 14:09:00 UTC+1100 2004

Categories:

I've created an ORM (Object-Relational Mapper) to aid in the development of a large system that I'm working on. It comes complete with a code-builder, etc.

One of the big challenges in my ORM was servicing atomic transactions specified on the client.

Initially I hacked together a solution that held a SqlTransaction open on the application server while multiple commands were synchronously issued by the client application. This obviously is a terrible thing to do, and was only an 'expedient' solution. I don't want to get into the COM+ world of distributed transactions, because really I don't need them as the client *is* capable of expressing all the data required for a 'transaction' in one request.

I reimplemented my solution so that a 'Save' command would create a Command object containing the Entity or Key and the Action that was to be performed. I then allowed a Command to have a list of sub Command objects. In this way, I could easily support creation of a 'serialization graph' and spit an atomic, but complex command at my app server. On the application server a Service object is selected for a Command based on its type. So an AddressCommand (that performs an Action on an Address) will be handled by the AddressService, etc. The ServerApplication.ExecuteCommand(..) implementation will check for 'sub Command' objects (via the Command.IsTransactionRequired interface) and create and manage a 'transaction' via the DAL (which remains pluggable, not tied to SQL Server alone) if needed. It will pass this transaction object to all service objects as needed.

Now I have a problem though, because I want to have 'custom' commands. The thing is a Command is really tightly coupled with a 1:1 mapping between the Command the the Entity (or Key) that it operates on. The fact that there are sub Commands is just an implementation detail, these sub Commands also have a 1:1 mapping with an Entity.

So now I'm going to expand on my thinking, and separate Command and Transaction. Previously, a Command 'was' a Transaction. The Command *could be* complex if required, by specifying 'sub Commands' that were carried out in the same database transaction. The idea being that if I was to go Client.Save() then I'd create a Command object to save the Client, but if that Client has a new Address in the Client.PostalAddress property, then I would also create a Command to create the Address, and then when servicing the Command that saves the Client I would first execute the Command that saved the Address inside the DB transaction on the app server, so I could specify the Address.Id for the Client.PostalAddress when I then saved the Client in the same transaction. This worked well. But now I have the problem of how to 'break apart' or 'recombine' these Save operations. At the moment, the client application can not specify 'break points' in it's Save operations. In this case, the Address object *must* be saved in order to save the Client. But if the Address was simply 'altered' rather than 'new' then I may not want to save the changes to Address when I save the Client in a certain UI scenario. This is a simple example, but obviously it can get much more complex.

So what I'm thinking about doing now is making my base Command object less tightly coupled to an 'Entity' and expanding my Action enum to include 'Complex' or 'Transaction' for example. At the moment, Action looks like this:

  public enum CommandAction {
    Create,
    Update,
    UpdateConcurrent,
    Delete,
    DeleteConcurrent,
  }

So, the idea is that Command simply describes an 'atomic unit of work' and typically this will just have a 1:1 mapping with an Entity. However, I can derive Transaction from Command to describe complex Commands. These are still 'atomic' because they are carried out as a single unit of work on the application server, however, I can create custom Transactions if I want an specify what happens 'between steps' on the app server. This should mean that a typical derived Command will simply be something that acts on a single Entity, but a typical derived Transaction will maintain a list of Command objects and between each Command certain custom things can happen. This means my client application can create a 'transaction' specifying all the data that the server will need to process the transaction and issue it in one hit, meaning that I can avoid the requirement of managing 'distributed' transactions (which are difficult and costly to performance).

So, now if I issue Client.Save() I could specify 'default' behavior as I liked depending on the 'default coupling' or 'break points' for related entities (for example, saving a Client may not save all related Projects by default, but may save the postal address). So the default implementation of Client.Save() will either generate a Command that simply saves the Client (and nothing more) or a Transaction that saves the Client and 'default' related entities. I can then create custom Transaction objects that encapsulate business rules, or if I like I can also just create an instance of Transaction (i.e. not a specialized derived instance) and stash Commands that need to be carried out in sequence. This way the UI can specify what it wants saved and how it wants it saved (or updated, deleted, etc) by creating its own Transaction.

So now I'm thinking that a Transaction is a Command, but a Command is not 'complex' until after it is a Transaction.

It's going to be a long day..

John.


Copyright © 2003-2005 John Elliot