A day in the life...

public class GeekEarth : Earth { }
posts - 26, comments - 8236, trackbacks - 0

Tuesday, November 30, 2010

ECO atomic operations

I’ve just created a simple class which I thought I’d share.

Account1.Balance += 10; Account2.Balance -= 10;

 

In this case we might expect the second line to throw an exception if the adjustment is not permitted, but the first line has already executed.  Obviously this isn’t a problem because we simply wouldn’t update the database, but sometimes you want an operation to occur in memory as an atomic operation; like this

 

using (var atomicOperation = new AtomicOperation(EcoSpace)) { Account1.Balance += 10; Account2.Balance -= 10; atomicOperation.Commit(); }

And so that is exactly what I wrote.  The class uses the UndoService to create/merge/remove undo blocks so it is even possible to nest atomic operations.

 

public class AtomicOperation : IDisposable { IUndoService UndoService; bool IsResolved; string UndoBlockName; public AtomicOperation(IUnitOfWork unitOfWork) { Contract.Requires(unitOfWork != null); Contract.Requires(unitOfWork.ObjectSpace != null); UndoBlockName = Guid.NewGuid().ToString(); UndoService = unitOfWork.ObjectSpace.GetEcoService<IUndoService>(); UndoService.StartUndoBlock(UndoBlockName); } public void Commit() { if (IsResolved) throw new InvalidOperationException("AtomicOperation has already been committed or rolled back"); IsResolved = true; int index = UndoService.UndoList.IndexOf(UndoBlockName); if (index > 0) { string nameOfBlockAbove = UndoService.UndoList[index - 1].Name; UndoService.UndoList.MergeBlocks(nameOfBlockAbove, UndoBlockName); } else { if (index > 0) UndoService.UndoList.RemoveBlock(UndoBlockName); if (UndoService.RedoList.IndexOf(UndoBlockName) > 0) UndoService.RedoList.RemoveBlock(UndoBlockName); } } public void Rollback() { if (IsResolved) throw new InvalidOperationException("AtomicOperation has already been committed or rolled back"); IsResolved = true; if (UndoService.UndoList.IndexOf(UndoBlockName) > -1) UndoService.UndoBlock(UndoBlockName); if (UndoService.RedoList.IndexOf(UndoBlockName) > -1) UndoService.RedoList.RemoveBlock(UndoBlockName); } void IDisposable.Dispose() { GC.SuppressFinalize(this); if (!IsResolved) Rollback(); } ~AtomicOperation() { throw new InvalidOperationException("AtomicOperation was not disposed, try using()"); } }

posted @ Tuesday, November 30, 2010 8:40 PM | Feedback (277) |

Powered by: