Click here to Skip to main content
12,825,359 members (40,613 online)
Click here to Skip to main content
Add your own
alternative version


20 bookmarked
Posted 8 Mar 2009

Transactions on object models

, 8 Mar 2009 GPL3
Rate this:
Please Sign up or sign in to vote.
Rollback or commit changes that you did on .NET objects.


Wouldn't it be nice if we could (like in a database) take an object-oriented domain model, start a transaction, do wild things with the data and relationships, and then eventually just roll back these changes? My opinion: Yes, it would! Especially if we tend to use as "less" as possible of the functionalities of a relational database and as much as possible the benefits of object orientation. In those system designs, the possibility of managing object model transactions is necessary. For the TechNewLogic "Stasy" framework - a high level implementation of the Unit-Of-Work design pattern (, I wrote a little demo extension that makes transactions possible.


  • Automatic tracking of property changes via a specialized lightweight .NET proxy.
  • The proxy inherits the entity types at runtime.
  • These types must be registered at the proxy generator (see example below).
  • Limitation: The entity classes of the object model have to be created via a factory method of the proxy generator.
  • Limitation: The entity classes must have a default (parameter-less) constructor.
  • Limitation: All properties of the entity classes must be declared as "virtual" so that the runtime inheritance mechanism of the proxy can work.
  • Limitation: If lists or collections are used in the entity classes, an implementation of ITransactionList has to be used (there is a standard implementation in the framework).


public class EntityClass1
    public EntityClass1()
        EntityClass2List = new TransactionList<EntityClass2>();
    public virtual int MyInt { get; set; } 
    public virtual TransactionList<EntityClass2> EntityClass2List { get; set; }

public class EntityClass2
    public virtual string MyString { get; set; }

Here, we have quite a simple object model. It consists of two classes: one has an aggregation to the other and some primitive properties.

The following code snippet demonstrates how to use the transaction framework. Basically, it works like this:

  • Create some data (we use our small object model, of course).
  • Begin a transaction.
  • Now, we do some stuff with our model, change values, insert some new entities, etc.
  • Rollback
  • Result: The object model looks as if nothing happened!
static void Main(string[] args)
    // Setup
    var transactionMonitor = new TransactionMonitor();
    var generator = new ProxyGenerator(

    // Create the model data
    var entity1 = generator.CreateProxy<EntityClass1>();
    entity1.MyInt = 100;
    AssertAreEqual(100, entity1.MyInt);

    var entity2 = entity1.EntityClass2List.Single();
    entity2.MyString = "Hallo";
    AssertAreEqual("Hallo", entity2.MyString);

    /// everything done from here will be tracked and eventually rolled back

    // change a value property of our entity1
    entity1.MyInt = 9999;
    AssertAreEqual(9999, entity1.MyInt); 

    // change a value property of our entity2
    entity2.MyString = "Welt";
    AssertAreEqual("Welt", entity2.MyString); 
    // add a new entity to the list of entity 1 and check if we had success
    var newEntity = generator.CreateProxy<EntityClass2>();
    AssertAreEqual(2, entity1.EntityClass2List.Count); 
    // remove the 'original' entity2; the only remaining
    // entity should be the new entity
    var checkEntity = entity1.EntityClass2List.Single();
    AssertAreEqual(newEntity, checkEntity); 
    /// Rollback all our changed
    // the value property of entity1
    AssertAreEqual(100, entity1.MyInt); 

    // there should be one entity in the entity list of entity1
    var checkEntity2 = entity1.EntityClass2List.Single();
    AssertAreEqual(entity2, checkEntity2); 

    // the value property of entity2
    AssertAreEqual("Hallo", entity2.MyString); 


static void AssertAreEqual(object o1, object o2)
    if (o1 == null && o2 == null)
    else if (o1 == null && o2 != null)
        throw new ApplicationException();
    else if (o1 != null && o2 == null)
        throw new     ApplicationException();
    else if (!o1.Equals(o2))
        throw new ApplicationException();


This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


About the Author

Ronald Schlenker
Software Developer (Senior)
Germany Germany
No Biography provided

You may also be interested in...


Comments and Discussions

QuestionDB Issue Pin
Bruce Zhang8-Mar-09 18:26
memberBruce Zhang8-Mar-09 18:26 
AnswerRe: DB Issue Pin
Ronald Schlenker8-Mar-09 22:33
memberRonald Schlenker8-Mar-09 22:33 
Hi Bruce,

Let me say it like this: What I described here is just one layer of a larger framework. This layer - the transaction layer - is not aware of the fact that there might be a database somewhere in your system; it just cares about your .Net object model. If you neeed synchronization with a database, you have to implement that on your own.

Additionally: As I described in the article, the implementation shown here is limited to one running transaction per time; I'm currently extending it for allowing concurrent access using the "Read-Committed" DB concurrency pattern.

May I ask which technology do you use for DB synchronization? Do you use some kind of Active Records?


GeneralRe: DB Issue Pin
Bruce Zhang8-Mar-09 22:52
memberBruce Zhang8-Mar-09 22:52 
GeneralRe: DB Issue Pin
Ronald Schlenker9-Mar-09 4:45
memberRonald Schlenker9-Mar-09 4:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170308.1 | Last Updated 8 Mar 2009
Article Copyright 2009 by Ronald Schlenker
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid