Click here to Skip to main content
Licence GPL3
First Posted 8 Mar 2009
Views 16,390
Downloads 61
Bookmarked 20 times

Transactions on object models

By Honk McSchlonk | 8 Mar 2009
Rollback or commit changes that you did on .NET objects.

1

2
2 votes, 40.0%
3
1 vote, 20.0%
4
2 votes, 40.0%
5
4.00/5 - 5 votes
μ 4.00, σa 1.75 [?]

Introduction

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 (http://martinfowler.com/eaaCatalog/unitOfWork.html), I wrote a little demo extension that makes transactions possible.

Summary

  • 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).

Example

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(
        new[]
        {
            typeof(EntityClass1),
            typeof(EntityClass2)
        },
        transactionMonitor);

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

    entity1.EntityClass2List.Add(generator.CreateProxy<EntityClass2>());
    var entity2 = entity1.EntityClass2List.Single();
    entity2.MyString = "Hallo";
    AssertAreEqual("Hallo", entity2.MyString);

    
    ///
    /// everything done from here will be tracked and eventually rolled back
    ///
    transactionMonitor.Begin(); 

    // 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>();
    entity1.EntityClass2List.Add(newEntity);
    AssertAreEqual(2, entity1.EntityClass2List.Count); 
    
    // remove the 'original' entity2; the only remaining
    // entity should be the new entity
    entity1.EntityClass2List.Remove(entity2);
    var checkEntity = entity1.EntityClass2List.Single();
    AssertAreEqual(newEntity, checkEntity); 
    
    ///
    /// Rollback all our changed
    /// 
    transactionMonitor.Rollback(); 
    
    // 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); 

    Console.ReadLine();
} 

static void AssertAreEqual(object o1, object o2)
{
    if (o1 == null && o2 == null)
        return;
    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();
}

License

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

About the Author

Honk McSchlonk



Germany Germany

Member


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionDB Issue PinmemberBruce Zhang18:26 8 Mar '09  
AnswerRe: DB Issue PinmemberRonald Schlenker22:33 8 Mar '09  
GeneralRe: DB Issue PinmemberBruce Zhang22:52 8 Mar '09  
GeneralRe: DB Issue PinmemberRonald Schlenker4:45 9 Mar '09  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    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 | Mobile
Web02 | 2.5.120209.1 | Last Updated 8 Mar 2009
Article Copyright 2009 by Honk McSchlonk
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid