Meeting the needs of your business from a distance

All-In-One Code Framework

by mark shiffer 9. September 2010 16:59

I ran across the All-In-One Code Framework today from Microsoft for the first time. I guess it has been around for a while, but I’d never noticed it was there. It appears to have a plethora of code examples for various development tasks. It may come in handy some day.

Here’s Microsoft’s description of it:

Microsoft All-In-One Code Framework delineates the framework and skeleton of Microsoft development techniques through typical sample codes in three popular programming languages (Visual C#, VB.NET, Visual C++). Each sample is elaborately selected, composed, and documented to demonstrate one frequently-asked, tested or used coding scenario based on our support experience in MSDN newsgroups and forums. If you are a software developer, you can fill the skeleton with blood, muscle and soul. If you are a software tester or a support engineer like us, you may extend the sample codes a little to fit your specific test scenario or refer your customer to this project if the customer's question coincides with what we collected.
Today is June 8th, 2010. The project has more than 390 code examples that cover 24 Microsoft development technologies like Azure, Windows 7 and Silverlight 3. The collection grows by six samples per week. You can find the up-to-date list of samples in All-In-One Code Framework Sample Catalog.

Tags: , ,

Programming | Research

Fun Coding Challenges

by mark shiffer 16. July 2010 17:03

Pex is an automated unit testing generation tool that Microsoft Research has had out for a while now. Essentially Pex generates various input parameters for your methods helping to find the variations that should be testing to get good code coverage.

The PexForFun website provides an interesting set of code challenges while using Pex to drive it. You are given a starter method that is stripped down to be barely functional and that fails the Pex generated tests. Your goal is to alter the method such that it will pass the tests without any outside knowledge as to what the code is supposed to do and without knowing the Pex unit tests until they fail. It is an interesting approach to advertising what capabilities Pex has and can be a little addicting too.

Tags:

Research | Programming

Development Resources for Any Language!

by mark shiffer 16. July 2010 16:56

Came across a website today called DevCheatSheet that contains a nice compilation of quick references for just about any language (and more) you can think of including: programming, scripting, markup, databases, version control, servers, ORM, blogs, websites, text editors and many other miscellaneous application.

Although fairly comprehensive there are missing pieces. I noticed Team Foundation Server (TFS) was missing from version control and Entity Framework (EF) was missing from ORM. Regardless should be a good place to find a reference for that language that you rarely use and need to remind your self of the syntax for.

Tags:

Programming | Research

Unit of Work Pattern for Entity Framework 4 and Unity

by Mark Shiffer 28. June 2010 13:43

Continuing from my last post on the Repository pattern…here is some background.

I am in the process of bringing up a new architecture for a project that I am working on that uses MVVM with WPF, WCF, Unity and Entity Framework 4 with Self Tracking Entities. One of the foundational items that is necessary to create as part of this architecture is a Repository to abstract the data store. As a related item, a proper Unit of Work pattern needs to be instantiated in order to provide transactional boundaries for some of the data processes. I will focus on the Unit of Work in this post, for more information on my repository implementation please see my previous post.

Before I started designing my approach I read several different attempts by others at implementing these patterns. Some were better than others, but in the end no one approach seemed to be a best fit for my application. However, the heaviest influence on my design came from NCommon, a library that contains implementations of commonly used design patterns when developing applications. If you haven’t looked at NCommon before, I would suggest taking a gander as it has some interesting stuff. However, for my purposes, it introduced too much complexity by trying to be a generic framework that applied to several different technologies, whereas, directing my approach to my specific set of technologies (while still abstracting mind you), made the code much more straight forward.

With Entity Framework it naturally works out that the ObjectContext is the unit of work itself. The ObjectContext is already caching all of the data changes that occur during its lifetime and only commits those when asked. So, at the core of my Unit of Work implementation is the ObjectContext. I have defined an IUnitOfWork interface which the ObjectContext implements to further abstract the concept. After that there are 3 core classes involved in my implementation of Unit of Work:

1. UnitOfWorkScope – The purpose of this class is to provide a quick fluid interface to place a unit of work around a block of code. This is the core class that is used by the ‘outside’ world to create transactional code. It’s intended usage pattern is:

   1: using (var scope = new UnitOfWorkScope())
   2: {
   3:     ...
   4:     scope.Commit();
   5: }

2. TransactionManager – The TransactionManager is in charge of placing a UnitOfWorkScope into a UnitOfWorkTransaction whether it be new or existing.

3. UnitOfWorkTransaction – This is the actual transaction that controls when, and if, work completed within a set of UnitOfWorkScopes will be committed to the data store. When a UnitOfWorkTransaction is instantiated it creates a new IUnitOfWork instance (ObjectContext) on which to act.

So the developer creates scopes, nesting additional scopes where needed or creating side-by-side scopes of a separate transactional boundary. When a scope is created, it asks the TransactionManager to be enlisted in a transaction. The TransactionManager finds or creates an UnitOfWorkTransaction and associates it with the UnitOfWorkScope. The UnitOfWorkTransaction then keeps a list of active scopes for the transaction. When any of the scopes is rolled back, the entire transaction is torn down. Once the last scope is committed, assuming no rollbacks have occurred, the UnitOfWorkTransaction flushes the IUnitOfWork effectively calling SaveChanges on the ObjectContext.

If you’ve read the Repository post prior to this, you may have noticed where unit of work was tied in making the process very seamless for the end developer. The CurrentObjectSet property of the repository class coordinates with the TransactionManager such that regardless of where the repository instance was created, it will join a transaction on the fly if one is active. In addition, ApplyChanges will only save to the data store if the repository instance is not under a transaction at that time.

So, let’s start with the interfaces for what set’s all of this up:

IUnitOfWork:

   1: /// <summary>
   2:  /// Unit of work interface. The EF ObjectContext serves as the unit of work. This interface provides a contract to interact with the EF ObjectContext
   3:  /// as a unit of work.s
   4:  /// </summary>
   5:  public interface IUnitOfWork : IDisposable
   6:  {
   7:      /// <summary>
   8:      /// Gets the context for this unit of work (EF Context serves as the actual unit of work).
   9:      /// </summary>
  10:      /// <value>The context.</value>
  11:      ObjectContext Context { get; }
  12:  
  13:      /// <summary>
  14:      /// Commits changes to the Context to the data store.
  15:      /// </summary>
  16:      void Flush();
  17:  
  18:      /// <summary>
  19:      /// Rollbacks changes to the Context.
  20:      /// </summary>
  21:      void Rollback();
  22:  }

IUnitOfWorkScope:

   1: /// <summary>
   2: /// Unit of work scope is the outward facing wrapper for developers to begin/enlist in a transaction. Scopes can be nested, in which case, once the last or outtermost
   3: /// scope is committed then the unit of work will be flushed/committed. If any scope exists/disposes before committing it will be rolled back, and any
   4: /// scopes upward in the chain will be rolled back as well. 
   5: /// </summary>
   6: public interface IUnitOfWorkScope : IDisposable
   7: {
   8:     /// <summary>
   9:     /// Marks the scope committed, triggering the unit of work to commit if this is the outtermost scope.
  10:     /// </summary>
  11:     void Commit();
  12:  
  13:     /// <summary>
  14:     /// Rollbacks this scope, triggering the unit of work to be rolled back.
  15:     /// </summary>
  16:     void Rollback();
  17: }

ITransactionManager:

   1: /// <summary>
   2: /// The Transaction Manager holds a list of active, isolated transactions within the system and acts as the entry point for a new unit of work scope. 
   3: /// </summary>
   4: public interface ITransactionManager
   5: {
   6:     /// <summary>
   7:     /// Gets the current EF context based upon the most recent transacion.
   8:     /// </summary>
   9:     /// <value>The current context.</value>
  10:     ObjectContext CurrentContext { get; }
  11:  
  12:     /// <summary>
  13:     /// Gets or sets the thread static operation context, the unique identifier for a wcf call across our system.
  14:     /// </summary>
  15:     /// <value>The operation context.</value>
  16:     /// <param name="operationContext">The operation context.</param>
  17:     Guid OperationContext { get; set; }
  18:  
  19:     /// <summary>
  20:     /// Enlists a <see cref="UnitOfWorkScope"/> instance with the transaction manager, either beginning a new transaction or attaching to an existing transaction.
  21:     /// </summary>
  22:     /// <param name="scope">bool. True if the scope should be enlisted in a new transaction, else
  23:     /// false if the scope should participate in the existing transaction when available</param>
  24:     /// <param name="newTransaction">if set to <c>true</c> [new transaction].</param>
  25:     /// <returns>
  26:     /// Transcation created or assigned to the scope.
  27:     /// </returns>
  28:     IUnitOfWorkTransaction EnlistScope(IUnitOfWorkScope scope, bool newTransaction);
  29: }

IUnitOfWorkTransaction:

   1: /// <summary>
   2: /// Unit Of Work Transaction keeps a list of active scopes for a given transaction and commits the unit of work if all scopes have been committed.
   3: /// </summary>
   4: public interface IUnitOfWorkTransaction : IDisposable
   5: {
   6:     /// <summary>
   7:     /// Occurs when [transaction disposing].
   8:     /// </summary>
   9:     event EventHandler<EventArgs> TransactionDisposing;
  10:  
  11:     /// <summary>
  12:     /// Gets the unit of work.
  13:     /// </summary>
  14:     /// <value>The unit of work.</value>
  15:     IUnitOfWork UnitOfWork { get; }
  16:  
  17:     /// <summary>
  18:     /// Gets a unique identifier for a series of related operations. Under WCF this is provided by its operation context which is unique for each call made to the service.
  19:     /// </summary>
  20:     /// <value>The operation context identifier.</value>
  21:     Guid OperationContext { get; }
  22:  
  23:     /// <summary>
  24:     /// Enlists the scope in the transaction
  25:     /// </summary>
  26:     /// <param name="scope">The scope.</param>
  27:     void EnlistScope(IUnitOfWorkScope scope);
  28:  
  29:     /// <summary>
  30:     /// Commits the scope, if this is the last scope that was enlisted, the unit of work will be flushed.
  31:     /// </summary>
  32:     /// <param name="scope">The scope.</param>
  33:     void CommitScope(IUnitOfWorkScope scope);
  34:  
  35:     /// <summary>
  36:     /// Rollbacks the scope, effectively rolling back the unit of work.
  37:     /// </summary>
  38:     /// <param name="scope">The scope.</param>
  39:     void RollbackScope(IUnitOfWorkScope scope);
  40: }

All pretty straight forward. The only special note here is the OperationContext. This is what helps to make the pattern work across threads. This is especially important with WCF involved, as each call to the server will be on its own thread. In addition, server job processes could spawn additional threads to perform their work and one would expect work completed on a child thread should join the transaction of its parent. I’ll talk more about this as we look at the implementations of the interfaces.

<UnitOfWork>:

   1: /// <summary> Provide business logic for the MSSWCModelContainer class 
   2: /// </summary>
   3: [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Need interface with IDisposable so that code can call base disposable generically.")]
   4: public partial class MSSWCModelContainer : IUnitOfWork
   5: {
   6:     /// <summary>
   7:     /// Gets the context.
   8:     /// </summary>
   9:     /// <value>The context.</value>
  10:     public ObjectContext Context
  11:     {
  12:         get { return this; }
  13:     }
  14:  
  15:     /// <summary> Persists all updates to the data source with the specified <see cref="T:System.Data.Objects.SaveOptions"/>.
  16:     /// </summary>
  17:     /// <param name="options">A <see cref="T:System.Data.Objects.SaveOptions"/> value that determines the behavior of the operation.</param>
  18:     /// <returns>
  19:     /// The number of objects in an <see cref="F:System.Data.EntityState.Added"/>, <see cref="F:System.Data.EntityState.Modified"/>, or <see cref="F:System.Data.EntityState.Deleted"/> state when <see cref="M:System.Data.Objects.ObjectContext.SaveChanges"/> was called.
  20:     /// </returns>
  21:     /// <exception cref="T:System.Data.OptimisticConcurrencyException">An optimistic concurrency violation has occurred.</exception>
  22:     public override int SaveChanges(SaveOptions options)
  23:     {
  24:         // Validate the state of each entity in the context
  25:         // before SaveChanges can succeed.
  26:         foreach (ObjectStateEntry entry in ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified))
  27:         {
  28:             if (!entry.IsRelationship)
  29:             {
  30:                 if (entry.Entity is IValidatingEntity)
  31:                 {
  32:                     ((IValidatingEntity)entry.Entity).Validate();
  33:                 }
  34:  
  35:                 if (entry.Entity is ISrsEntity)
  36:                 {
  37:                     ApplyLastModifiedInformation((ISrsEntity)entry.Entity);
  38:                 }
  39:             }
  40:         }
  41:  
  42:         List<IObjectWithChangeTracker> entitiesToReset = null;
  43:  
  44:         if ((options & SaveOptions.AcceptAllChangesAfterSave) == SaveOptions.AcceptAllChangesAfterSave)
  45:         {
  46:             var q = from entry in ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified)
  47:                     where entry.Entity is IObjectWithChangeTracker
  48:                     select (IObjectWithChangeTracker)entry.Entity;
  49:  
  50:             entitiesToReset = q.ToList();
  51:         }
  52:  
  53:         var result = base.SaveChanges(options);
  54:  
  55:         if (entitiesToReset != null)
  56:         {
  57:             foreach (var entity in entitiesToReset)
  58:             {
  59:                 entity.AcceptChanges();
  60:             }
  61:         }
  62:  
  63:         return result;
  64:     }
  65:  
  66:     /// <summary>
  67:     /// Commits this instance.
  68:     /// </summary>
  69:     public void Flush()
  70:     {
  71:         this.SaveChanges();
  72:     }
  73:  
  74:     /// <summary>
  75:     /// Rollbacks this instance.
  76:     /// </summary>
  77:     public void Rollback()
  78:     {
  79:         // rolling back invalidates this object context for any future use, so dispose it.
  80:         Dispose();
  81:     }
  82:  
  83:     /// <summary>
  84:     /// Writes the last modified date/time and user information to the entity.
  85:     /// </summary>
  86:     /// <param name="entity">Entity to apply last modified info to.</param>
  87:     private static void ApplyLastModifiedInformation(ISrsEntity entity)
  88:     {
  89:         entity.LastModified = DateTime.Now;
  90:         if (ServiceSecurityContext.Current != null)
  91:         {
  92:             entity.ModifiedBy = ServiceSecurityContext.Current.WindowsIdentity.Name;
  93:         }
  94:     }
  95: }

Not much to see here, moving on… Ignore the nastiness of the SaveChanges call and the AcceptChanges loop. Once again, Entity Framework has some issues.

UnitOfWorkScope:

   1: /// <summary>
   2: /// Unit of work scope is the outward facing wrapper for developers to begin/enlist in a transaction. Scopes can be nested, in which case, once the last or outtermost
   3: /// scope is committed then the unit of work will be flushed/committed. If any scope exists/disposes before committing it will be rolled back, and any
   4: /// scopes upward in the chain will be rolled back as well.
   5: /// </summary>
   6: public class UnitOfWorkScope : IUnitOfWorkScope, IDisposable
   7: {
   8:     private bool disposed;
   9:     private bool commitAttempted;
  10:     private IUnitOfWorkTransaction transaction;
  11:     private ITransactionManager transactionManager;
  12:  
  13:     /// <summary>
  14:     /// Initializes a new instance of the <see cref="UnitOfWorkScope"/> class with the <see cref="System.Data.IsolationLevel.Serializable"/>
  15:     /// transaction isolation level.
  16:     /// </summary>
  17:     public UnitOfWorkScope()
  18:         : this(false)
  19:     {
  20:     }
  21:  
  22:     /// <summary>
  23:     /// Initializes a new instance of the <see cref="UnitOfWorkScope"/> class.
  24:     /// </summary>
  25:     /// <param name="newTransaction">To create a new scope that does not enlist in an existing ambient
  26:     /// <see cref="UnitOfWorkScope"/> or <see cref="TransactionScope"/>, specify new, otherwise specify false.</param>
  27:     public UnitOfWorkScope(bool newTransaction)
  28:     {
  29:         transaction = TransactionManager.EnlistScope(this, newTransaction);
  30:         transaction.TransactionDisposing += new EventHandler<EventArgs>(OnTransactionDisposing);
  31:         ScopeStatus = UnitOfWorkScopeStatus.Active;
  32:     }
  33:  
  34:     /// <summary>
  35:     /// Initializes a new instance of the <see cref="UnitOfWorkScope"/> class and enlists in a specific existing transaction.
  36:     /// </summary>
  37:     /// <param name="transaction">The transaction to enlist the new scope in.</param>
  38:     public UnitOfWorkScope(IUnitOfWorkTransaction transaction)
  39:     {
  40:         if (transaction != null)
  41:         {
  42:             this.transaction = transaction;
  43:             transaction.EnlistScope(this);
  44:             ScopeStatus = UnitOfWorkScopeStatus.Active;
  45:             transaction.TransactionDisposing += new EventHandler<EventArgs>(OnTransactionDisposing);
  46:         }
  47:         else
  48:         {
  49:             // if the transaction wasn't specified then call the transaction manager to enlist the scope as it will find/create a transaction for the scope to attach to.
  50:             transaction = TransactionManager.EnlistScope(this, false);
  51:             ScopeStatus = UnitOfWorkScopeStatus.Active;
  52:             transaction.TransactionDisposing += new EventHandler<EventArgs>(OnTransactionDisposing);
  53:         }
  54:     }
  55:  
  56:     /// <summary>
  57:     /// Event fired when the scope is comitting.
  58:     /// </summary>
  59:     public event EventHandler<EventArgs> ScopeComitting;
  60:  
  61:     /// <summary>
  62:     /// Event fired when the scope is rollingback.
  63:     /// </summary>
  64:     public event EventHandler<EventArgs> ScopeRollingback;
  65:  
  66:     /// <summary>
  67:     /// Gets the current scope status.
  68:     /// </summary>
  69:     /// <value>The scope status.</value>
  70:     public UnitOfWorkScopeStatus ScopeStatus
  71:     {
  72:         get;
  73:         private set;
  74:     }
  75:  
  76:     /// <summary>
  77:     /// Gets the transaction manager.
  78:     /// </summary>
  79:     /// <value>The transaction manager.</value>
  80:     private ITransactionManager TransactionManager
  81:     {
  82:         get
  83:         {
  84:             if (transactionManager == null)
  85:             {
  86:                 transactionManager = ServiceLocator.Current.GetInstance<ITransactionManager>();
  87:             }
  88:  
  89:             return transactionManager;
  90:         }
  91:     }
  92:  
  93:     /// <summary>
  94:     /// Commits the current running transaction in the scope.
  95:     /// </summary>
  96:     public void Commit()
  97:     {
  98:         if (disposed)
  99:         {
 100:             throw new ObjectDisposedException("Cannot commit a disposed UnitOfWorkScope instance.");
 101:         }
 102:  
 103:         commitAttempted = true;
 104:  
 105:         if (ScopeComitting != null)
 106:         {
 107:             ScopeComitting(this, EventArgs.Empty);
 108:         }
 109:  
 110:         if (transaction != null)
 111:         {
 112:             transaction.CommitScope(this);
 113:         }
 114:  
 115:         ScopeStatus = UnitOfWorkScopeStatus.Complete;
 116:     }
 117:  
 118:     /// <summary>
 119:     /// Rollback the unit of work.
 120:     /// </summary>
 121:     public void Rollback()
 122:     {
 123:         if (ScopeRollingback != null)
 124:         {
 125:             ScopeRollingback(this, EventArgs.Empty);
 126:         }
 127:  
 128:         if (transaction != null)
 129:         {
 130:             transaction.RollbackScope(this);
 131:         }
 132:  
 133:         ScopeStatus = UnitOfWorkScopeStatus.Complete;
 134:     }
 135:  
 136:     /// <summary>
 137:     /// Disposes off the <see cref="UnitOfWorkScope"/> insance.
 138:     /// </summary>
 139:     public void Dispose()
 140:     {
 141:         Dispose(true);
 142:         GC.SuppressFinalize(this);
 143:     }
 144:  
 145:     /// <summary>
 146:     /// Disposes off the managed and un-managed resources used.
 147:     /// </summary>
 148:     /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
 149:     private void Dispose(bool disposing)
 150:     {
 151:         if (disposed)
 152:         {
 153:             return;
 154:         }
 155:  
 156:         if (disposing)
 157:         {
 158:             try
 159:             {
 160:                 if (!commitAttempted)
 161:                 {
 162:                     Rollback();
 163:                 }
 164:             }
 165:             finally
 166:             {
 167:                 ScopeComitting = null;
 168:                 ScopeRollingback = null;
 169:                 disposed = true;
 170:             }
 171:         }
 172:     }
 173:  
 174:     /// <summary>
 175:     /// Handles the TransactionDisposing event of the transaction control.
 176:     /// </summary>
 177:     /// <param name="sender">The source of the event.</param>
 178:     /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
 179:     private void OnTransactionDisposing(object sender, EventArgs e)
 180:     {
 181:         transaction.TransactionDisposing -= new EventHandler<EventArgs>(OnTransactionDisposing);
 182:         transaction = null;
 183:         ScopeStatus = UnitOfWorkScopeStatus.Complete;
 184:     }
 185: }

Again pretty straight forward. The TransactionManager that the scope uses for enlisting is service located, eventually pulled from Unity. This is done to keep the usage scenario fluent, otherwise each time a scope is instantiated a TransactionManager would have to be found to inject into the scope. That would either result in a lot of calls to service location spread around the code, or in the Unity container being passed around. Both of which are undesirable.

Take note, too, that disposing a scope will automatically trigger a rollback unless the scope was explicitly committed prior to the disposal via a call to Commit(). Also note, that additional flexibility is provided via the constructor overloads, allowing a UnitOfWorkScope to explicitly begin a new transaction or to enlist in a specific existing transaction. The default behavior is to enlist in the existing ambient transaction if one exists, otherwise to create one.

TransactionManager:

   1: /// <summary>
   2: /// The Transaction Manager holds a list of active, isolated transactions within the system and acts as the entry point for a new unit of work scope. 
   3: /// </summary>
   4: public class TransactionManager : ITransactionManager, IDisposable
   5: {
   6:     /// <summary>
   7:     /// Dictionary of operation contexts to transactions operating under that context
   8:     /// </summary>
   9:     private readonly Dictionary<Guid, List<IUnitOfWorkTransaction>> transactionLists = new Dictionary<Guid, List<IUnitOfWorkTransaction>>();
  10:  
  11:     [ThreadStatic]
  12:     private static Guid operationContext;
  13:  
  14:     private bool disposed;
  15:     private object transactionsLockObject = new object();
  16:     private IUnitOfWorkTransactionFactory transactionFactory;
  17:  
  18:     /// <summary>
  19:     /// Initializes a new instance of the <see cref="TransactionManager"/> class.
  20:     /// </summary>
  21:     /// <param name="transactionFactory">The transaction factory.</param>
  22:     public TransactionManager(IUnitOfWorkTransactionFactory transactionFactory)
  23:     {
  24:         this.transactionFactory = transactionFactory;
  25:     }
  26:  
  27:     /// <summary>
  28:     /// Gets the current context of the most recent transaction's unit of work.
  29:     /// </summary>
  30:     /// <value>The current context.</value>
  31:     public ObjectContext CurrentContext
  32:     {
  33:         get
  34:         {
  35:             if (CurrentTransaction != null)
  36:             {
  37:                 return CurrentTransaction.UnitOfWork.Context;
  38:             }
  39:             else
  40:             {
  41:                 return null;
  42:             }
  43:         }
  44:     }
  45:  
  46:     /// <summary>
  47:     /// Gets or sets the operation context that the current thread is running under.
  48:     /// Transactions are tied to an operation context, so that additional scopes that join a transaction should only join if they belong to the same context.
  49:     /// This value is currently being set in the AuthorizationPolicy so that each call to WCF tags its thread with a unique context. If new threads are spawned
  50:     /// by processes, they must manually copy the operation context from the main thread to their sub-threads.
  51:     /// </summary>
  52:     /// <value>The operation context, unique per wcf call.</value>
  53:     /// <param name="operationContext">The operation context.</param>
  54:     public Guid OperationContext
  55:     {
  56:         get
  57:         {
  58:             return operationContext;
  59:         }
  60:  
  61:         set
  62:         {
  63:             operationContext = value;
  64:         }
  65:     }
  66:  
  67:     /// <summary>
  68:     /// Gets the most recent transaction.
  69:     /// </summary>
  70:     /// <value>The current transaction.</value>
  71:     private IUnitOfWorkTransaction CurrentTransaction
  72:     {
  73:         get
  74:         {
  75:             lock (transactionsLockObject)
  76:             {
  77:                 List<IUnitOfWorkTransaction> transactions;
  78:                 if (transactionLists.TryGetValue(OperationContext, out transactions))
  79:                 {
  80:                     if (transactions.Count > 0)
  81:                     {
  82:                         return transactions[transactions.Count - 1];
  83:                     }
  84:                 }
  85:  
  86:                 return null;
  87:             }
  88:         }
  89:     }
  90:  
  91:     /// <summary>
  92:     /// Enlists a <see cref="UnitOfWorkScope"/> instance with the transaction manager.
  93:     /// </summary>
  94:     /// <param name="scope">bool. True if the scope should be enlisted in a new transaction, else
  95:     /// false if the scope should participate in the existing transaction</param>
  96:     /// <param name="newTransaction">if set to <c>true</c> [new transaction].</param>
  97:     /// <returns>
  98:     /// Transcation created or assigned to the scope.
  99:     /// </returns>
 100:     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Managed outside of this scope.")]
 101:     public IUnitOfWorkTransaction EnlistScope(IUnitOfWorkScope scope, bool newTransaction)
 102:     {
 103:         if (newTransaction || CurrentTransaction == null)
 104:         {
 105:             IUnitOfWorkTransaction transaction = transactionFactory.CreateUnitOfWorkTransaction(OperationContext);
 106:             transaction.TransactionDisposing += OnTransactionDisposing;
 107:  
 108:             lock (transactionsLockObject)
 109:             {
 110:                 transaction.EnlistScope(scope);
 111:                 List<IUnitOfWorkTransaction> transactions;
 112:                 if (!transactionLists.TryGetValue(OperationContext, out transactions))
 113:                 {
 114:                     transactions = new List<IUnitOfWorkTransaction>();
 115:                     transactionLists.Add(OperationContext, transactions);
 116:                 }
 117:  
 118:                 transactions.Add(transaction);
 119:             }
 120:  
 121:             return transaction;
 122:         }
 123:         else
 124:         {
 125:             CurrentTransaction.EnlistScope(scope);
 126:             return CurrentTransaction;
 127:         }
 128:     }
 129:  
 130:     /// <summary>
 131:     /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 132:     /// </summary>
 133:     /// <filterpriority>2</filterpriority>
 134:     public void Dispose()
 135:     {
 136:         Dispose(true);
 137:         GC.SuppressFinalize(this);
 138:     }
 139:  
 140:     /// <summary>
 141:     /// Releases unmanaged and - optionally - managed resources
 142:     /// </summary>
 143:     /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
 144:     private void Dispose(bool disposing)
 145:     {
 146:         if (disposed)
 147:         {
 148:             return;
 149:         }
 150:  
 151:         if (disposing)
 152:         {
 153:             lock (transactionsLockObject)
 154:             {
 155:                 if (transactionLists != null && transactionLists.Count > 0)
 156:                 {
 157:                     foreach (var kvp in transactionLists)
 158:                     {
 159:                         foreach (var transaction in kvp.Value)
 160:                         {
 161:                             transaction.TransactionDisposing -= OnTransactionDisposing;
 162:                             transaction.Dispose();
 163:                         }
 164:                     }
 165:  
 166:                     transactionLists.Clear();
 167:                 }
 168:             }
 169:         }
 170:  
 171:         disposed = true;
 172:     }
 173:  
 174:     /// <summary>
 175:     /// Called when [transaction disposing].
 176:     /// </summary>
 177:     /// <param name="sender">The sender.</param>
 178:     /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
 179:     private void OnTransactionDisposing(object sender, EventArgs e)
 180:     {
 181:         IUnitOfWorkTransaction transaction = sender as IUnitOfWorkTransaction;
 182:         if (transaction != null)
 183:         {
 184:             transaction.TransactionDisposing -= OnTransactionDisposing;
 185:             lock (transactionsLockObject)
 186:             {
 187:                 List<IUnitOfWorkTransaction> transactions;
 188:                 if (transactionLists.TryGetValue(transaction.OperationContext, out transactions))
 189:                 {
 190:                     if (transactions.Contains(transaction))
 191:                     {
 192:                         transactions.Remove(transaction);
 193:                     }
 194:                 }
 195:             }
 196:         }
 197:     }

It’s getting a little more interesting now. One TransactionManager will exist for the entire WCF service, requiring some coordination of the active transactions, especially when one thinks about the threading that is happening in the service. The private field transactionLists, tracks all open transactions by their OperationContext. The OperationContext is simply a Guid that is set at the very beginning of each Wcf Service call. Take special note that the context is marked as ThreadStatic, so that one instance of operationContext exists for each thread, even though there is only one instance of the TransactionManager for the service as a whole. If a job process instantiates child threads to complete its work, it is the responsibility of the coder at that time to carry the operation context through and to set it on the TransactionManager.

UnitOfWorkTransaction:

   1: /// <summary>
   2: /// Unit Of Work Transaction keeps a list of active scopes for a given transaction and commits the unit of work if all scopes have been committed.
   3: /// </summary>
   4: public class UnitOfWorkTransaction : IUnitOfWorkTransaction, IDisposable
   5: {
   6:     private bool disposed;
   7:     private IUnitOfWork unitOfWork;
   8:     private IList<IUnitOfWorkScope> attachedScopes = new List<IUnitOfWorkScope>();
   9:     private object attachedScopesLock = new object();
  10:  
  11:     /// <summary>
  12:     /// Initializes a new instance of the <see cref="UnitOfWorkTransaction"/> class.
  13:     /// </summary>
  14:     /// <param name="unitOfWorkFactory">The context factory; used to create a new unit of work instance.</param>
  15:     /// <param name="operationContext">The operation context, a unique identifier for each WCF call in our system, stored in TransactionManager's thread static property.</param>
  16:     public UnitOfWorkTransaction(IUnitOfWorkFactory unitOfWorkFactory, Guid operationContext)
  17:     {
  18:         if (unitOfWorkFactory == null)
  19:         {
  20:             throw new ArgumentNullException("unitOfWorkFactory");
  21:         }
  22:  
  23:         this.unitOfWork = unitOfWorkFactory.CreateUnitOfWork();
  24:  
  25:         this.OperationContext = operationContext;
  26:     }
  27:  
  28:     /// <summary>
  29:     /// Raised when the transaction is disposing.
  30:     /// </summary>
  31:     public event EventHandler<EventArgs> TransactionDisposing;
  32:  
  33:     /// <summary>
  34:     /// Gets the <see cref="IUnitOfWork"/> instance managed by the 
  35:     /// <see cref="UnitOfWorkTransaction"/> instance.
  36:     /// </summary>
  37:     public IUnitOfWork UnitOfWork
  38:     {
  39:         get { return unitOfWork; }
  40:     }
  41:  
  42:     /// <summary>
  43:     /// Gets the thread id for the transaction. Transactions are tied to a thread, so that additional scopes that join a transaction should only join if they belong to the same thread.
  44:     /// </summary>
  45:     /// <value>The thread id.</value>
  46:     public Guid OperationContext
  47:     {
  48:         get;
  49:         private set;
  50:     }
  51:  
  52:     /// <summary>
  53:     /// Attaches a <see cref="UnitOfWorkScope"/> instance to the 
  54:     /// <see cref="UnitOfWorkTransaction"/> instance.
  55:     /// </summary>
  56:     /// <param name="scope">The <see cref="UnitOfWorkScope"/> instance to attach.</param>
  57:     public void EnlistScope(IUnitOfWorkScope scope)
  58:     {
  59:         if (scope == null)
  60:         {
  61:             throw new ArgumentNullException("scope");
  62:         }
  63:  
  64:         if (!attachedScopes.Contains(scope))
  65:         {
  66:             lock (attachedScopesLock)
  67:             {
  68:                 if (!attachedScopes.Contains(scope))
  69:                 {
  70:                     attachedScopes.Add(scope);
  71:                 }
  72:             }
  73:         }
  74:     }
  75:  
  76:     /// <summary>
  77:     /// Callback executed when an enlisted scope has comitted.
  78:     /// </summary>
  79:     /// <param name="scope">The scope.</param>
  80:     public void CommitScope(IUnitOfWorkScope scope)
  81:     {
  82:         if (disposed)
  83:         {
  84:             throw new ObjectDisposedException("The transaction attached to the scope has already been disposed.");
  85:         }
  86:  
  87:         lock (attachedScopesLock)
  88:         {
  89:             if (!attachedScopes.Contains(scope))
  90:             {
  91:                 throw new InvalidOperationException("The scope being comitted is not attached to the current transaction.");
  92:             }
  93:  
  94:             attachedScopes.Remove(scope);
  95:             if (attachedScopes.Count == 0)
  96:             {
  97:                 try
  98:                 {
  99:                     unitOfWork.Flush();
 100:                 }
 101:                 finally
 102:                 {
 103:                     // Dispose the transaction after comitting.
 104:                     Dispose();
 105:                 }
 106:             }
 107:         }
 108:     }
 109:  
 110:     /// <summary>
 111:     /// Callback executed when an enlisted scope is rolledback.
 112:     /// </summary>
 113:     /// <param name="scope">The scope.</param>
 114:     public void RollbackScope(IUnitOfWorkScope scope)
 115:     {
 116:         if (disposed)
 117:         {
 118:             throw new ObjectDisposedException("The transaction attached to the scope has already been disposed.");
 119:         }
 120:  
 121:         // dispose this transcation which will notify via TransactionDisposing all scopes that were attached that the 
 122:         // transaction is being rolled back
 123:         Dispose();
 124:     }
 125:  
 126:     /// <summary>
 127:     /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 128:     /// </summary>
 129:     /// <filterpriority>2</filterpriority>
 130:     public void Dispose()
 131:     {
 132:         Dispose(true);
 133:         GC.SuppressFinalize(this);
 134:     }
 135:  
 136:     /// <summary>
 137:     /// Releases unmanaged and - optionally - managed resources
 138:     /// </summary>
 139:     /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
 140:     private void Dispose(bool disposing)
 141:     {
 142:         if (disposed)
 143:         {
 144:             return;
 145:         }
 146:  
 147:         if (disposing)
 148:         {
 149:             // notify all who care that this transaction is done.
 150:             if (TransactionDisposing != null)
 151:             {
 152:                 TransactionDisposing(this, EventArgs.Empty);
 153:             }
 154:  
 155:             // dispose of the unit of work since it was created for this transaction specifically
 156:             if (unitOfWork != null)
 157:             {
 158:                 unitOfWork.Dispose();
 159:             }
 160:  
 161:             lock (attachedScopesLock)
 162:             {
 163:                 attachedScopes.Clear();
 164:                 attachedScopes = null;
 165:             }
 166:  
 167:             TransactionDisposing = null;
 168:             unitOfWork = null;
 169:             disposed = true;
 170:         }
 171:     }
 172: }

Nothing surprising in this implementation given the previous discussion. The UnitOfWorkTransaction then keeps a list of active scopes for the transaction. When any of the scopes is rolled back, the entire transaction is torn down. Once the last scope is committed, assuming no roll backs have occurred, the UnitOfWorkTransaction flushes the IUnitOfWork effectively calling SaveChanges on the ObjectContext.

That’s it folks. I left out a few of the factor interfaces as they are just boring.

Tags: , ,

Programming

Repository Pattern with Entity Framework 4

by Mark Shiffer 28. June 2010 13:41

An original post for once! :-)

I am in the process of bringing up a new architecture for a project that I am working on that uses MVVM with WPF, WCF, Unity and Entity Framework 4 with Self Tracking Entities. One of the foundational items that is necessary to create as part of this architecture is a Repository to abstract the data store. As a related item, a proper Unit of Work pattern needs to be instantiated in order to provide transactional boundaries for some of the data processes. I will talk more about Unit of Work in my next post, but the following is what I came up with to implement the Repository pattern.

Before I started designing my approach I read several different attempts by others at implementing these patterns. Some were better than others, but in the end no one approach seemed to be a best fit for my application. However, the heaviest influence on my design came from NCommon, a library that contains implementations of commonly used design patterns when developing applications. If you haven’t looked at NCommon before, I would suggest taking a gander as it has some interesting stuff. However, for my purposes, it introduced too much complexity by trying to be a generic framework that applied to several different technologies, whereas, directing my approach to my specific set of technologies (while still abstracting mind you), made the code much more straight forward.

The Repository interface contains the standard set of Find methods that you would expect a repository to have using predicate Expressions in order to pass through to LINQ. This makes it extremely flexible and easy to use while still remaining type safe to call. In addition, two ApplyChanges methods are provided to allow for add, modify, deletes via Self-Tracking Entities, and a Refresh method to force an entity to re-load its values from the data store.

Repository Interface:

   1: /// <summary>Base interface for all repositories 
   2: /// </summary>
   3: /// <typeparam name="T">Aggregate type the repository is serving</typeparam>
   4: public interface IRepository<T> : IDisposable where T : class, IObjectWithChangeTracker
   5: {
   6:     /// <summary>
   7:     /// Return the entire set of persisted items
   8:     /// </summary>
   9:     /// <param name="includes">Sub-entities to include.</param>
  10:     /// <returns>Collection of all persisted items</returns>
  11:     IList<T> FindAll(params string[] includes);
  12:  
  13:     /// <summary>
  14:     /// The first element in source that passes the test in predicate
  15:     /// </summary>
  16:     /// <param name="predicate">The predicate.</param>
  17:     /// <param name="includes">The includes.</param>
  18:     /// <returns>The first element in source that passes the test in predicate.</returns>
  19:     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Intended")]
  20:     T First(Expression<Func<T, bool>> predicate, params string[] includes);
  21:  
  22:     /// <summary>
  23:     /// Gets the first element of a sequence, or a default value if the sequence
  24:     /// contains no elements.
  25:     /// </summary>
  26:     /// <param name="predicate">The predicate.</param>
  27:     /// <param name="includes">The includes.</param>
  28:     /// <returns>Returns the first element of a sequence, or a default value if the sequence
  29:     /// contains no elements.</returns>
  30:     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Intended")]
  31:     T FirstOrDefault(Expression<Func<T, bool>> predicate, params string[] includes);
  32:  
  33:     /// <summary>
  34:     /// Gets the single element of the input sequence.
  35:     /// </summary>
  36:     /// <param name="predicate">The predicate.</param>
  37:     /// <param name="includes">The includes.</param>
  38:     /// <returns>The single element of the input sequence.</returns>
  39:     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Intended"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Single", Justification = "Intended")]
  40:     T Single(Expression<Func<T, bool>> predicate, params string[] includes);
  41:  
  42:     /// <summary>
  43:     /// Gest a collection of all persisted items that pass the test in the predicate
  44:     /// </summary>
  45:     /// <param name="predicate">The predicate.</param>
  46:     /// <param name="includes">The includes.</param>
  47:     /// <returns>Collection of all persisted items that pass the test in the predicate</returns>
  48:     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Intended")]
  49:     IList<T> Find(Expression<Func<T, bool>> predicate, params string[] includes);
  50:  
  51:     /// <summary>
  52:     /// Persist changes a single entity to storage
  53:     /// </summary>
  54:     /// <param name="toSave">Entity to save</param>
  55:     void ApplyChanges(T toSave);
  56:  
  57:     /// <summary> Persist changes a set of entities to storage
  58:     /// </summary>
  59:     /// <param name="toSave">Collection of entities to save</param>
  60:     void ApplyChanges(IEnumerable<T> toSave);
  61:  
  62:     /// <summary>
  63:     /// Refreshes the specified entities from the data store.
  64:     /// </summary>
  65:     /// <param name="entities">The entities.</param>
  66:     void Refresh(params T[] entities);
  67: }

Two generic implementations are provided. In order to deal with how Entity Framework handles the hierarchy of an aggregate, we need to know about both the base type of the aggregate and the final concrete type. For example, if you have an Employee entity that descends from a person Entity, the ObjectSet in Entity Framework is retrieved via Person and the OfType<T>() method is used with the concrete type to get only Employee entities. So, Repository<BaseType> is provided as a quick way to access the repository when there is no hierarchy (BaseType=ConcreteType). Repository<BaseType, ConcreteType> is where the meat of the implementation is.

The majority of the class is self-explanatory from the code, just a couple of things to mention:

1. Object Sets – I customized the T4 template for the Entity Framework ObjectContext to include a GetObjectSet method. This method allows me to tap into the helper object sets that the context already contains in a generic manner and reuse them across the life of a context.

2. ApplyToContext – This method is a bit messy, frankly, because Entity Framework itself is a bit messy at times. The ApplyChanges method of the ObjectContext in Entity Framework only works when the entity you are trying to save was loaded from outside of the context, otherwise the changes are not recognized properly. So I make a call to TryGetObjectStateEntry to see if my entity was previously loaded and then call ChangeObjectState for a delete or ApplyCurrentValues for a modify based upon the Self Tracking Entities state.

Repository Implementation:

   1: /// <summary>
   2: /// Simple entity repository
   3: /// </summary>
   4: /// <typeparam name="BaseType">Base class type of entity being managed by the repository</typeparam>
   5: [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "Makes sense in this circumstance.")]
   6: public class Repository<BaseType> : Repository<BaseType, BaseType>
   7:     where BaseType : class, IObjectWithChangeTracker
   8: {
   9:     /// <summary>
  10:     /// Initializes a new instance of the <see cref="Repository&lt;BaseType&gt;"/> class.
  11:     /// </summary>
  12:     /// <param name="contextFactory">The context factory.</param>
  13:     /// <param name="transactionManager">The transaction manager.</param>
  14:     public Repository(IContextFactory contextFactory, ITransactionManager transactionManager)
  15:         : base(contextFactory, transactionManager)
  16:     {
  17:     }
  18: }
  19:  
  20: /// <summary>Base class for entity repositories 
  21: /// </summary>
  22: /// <typeparam name="BaseType">Base class type of entity being managed by the repository</typeparam>
  23: /// <typeparam name="ConcreteType">Concrete (derived) class type of entity being managed by the repository</typeparam>
  24: public class Repository<BaseType, ConcreteType> : IRepository<ConcreteType>, IDisposable
  25:     where BaseType : class, IObjectWithChangeTracker
  26:     where ConcreteType : class, BaseType
  27: {
  28:     private ITransactionManager transactionManager;
  29:     private ObjectContext localContext;
  30:     private bool disposed;
  31:  
  32:     // hide the context from descendants, they should not be able to get to a context directly if we can help it. They can get to it through the ObjectSet which
  33:     // we can't hide, but make it difficult to keep the repository single focused.
  34:     private IContextFactory contextFactory;
  35:  
  36:     /// <summary>
  37:     /// Initializes a new instance of the <see cref="Repository{BaseType,ConcreteType}"/> class.
dding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">  38:     /// </summary>
  39:     /// <param name="contextFactory">Factory that generates ObjectContext objects.</param>
  40:     /// <param name="transactionManager">The transaction manager.</param>
  41:     public Repository(IContextFactory contextFactory, ITransactionManager transactionManager)
  42:     {
  43:         this.transactionManager = transactionManager;
  44:         this.contextFactory = contextFactory;
  45:     }
  46:  
  47:     /// <summary>
  48:     /// Gets the object set to act on given the current transaction state
  49:     /// </summary>
  50:     /// <value>The current object set.</value>
  51:     /// <returns>The ObjectSet to use for this repository</returns>
  52:     protected ObjectSet<BaseType> CurrentObjectSet
  53:     {
  54:         get
  55:         {
  56:             // if currently in a transaction, then assume it's context, otherwise use a locally created one.
  57:             ObjectContext context = TransactionManager != null ? TransactionManager.CurrentContext : null;
  58:  
  59:             // create a context and manage its life if we are not already under a transaction scope
  60:             if (context == null)
  61:             {
  62:                 if (localContext == null)
  63:                 {
  64:                     localContext = contextFactory.CreateContext();
  65:                 }
  66:  
  67:                 context = localContext;
  68:             }
  69:  
  70:             return ((SrsModelContainer)context).GetObjectSet<BaseType>();
  71:         }
  72:     }
  73:  
  74:     /// <summary>
  75:     /// Gets the transaction manager.
  76:     /// </summary>
  77:     /// <value>The transaction manager.</value>
  78:     private ITransactionManager TransactionManager
  79:     {
  80:         get
  81:         {
  82:             return transactionManager;
  83:         }
  84:     }
  85:  
  86:     /// <summary>
  87:     /// Gets the first element in source that passes the test in predicate.
  88:     /// </summary>
  89:     /// <param name="predicate">The predicate.</param>
  90:     /// <param name="includes">The includes.</param>
  91:     /// <returns>
  92:     /// The first element in source that passes the test in predicate.
  93:     /// </returns>
  94:     public ConcreteType First(Expression<Func<ConcreteType, bool>> predicate, params string[] includes)
  95:     {
  96:         return GetObjectSet(includes).First(predicate);
  97:     }
  98:  
  99:     /// <summary>
 100:     /// Returns the first element of a sequence, or a default value if the sequence
 101:     /// contains no elements
 102:     /// </summary>
 103:     /// <param name="predicate">The predicate.</param>
 104:     /// <param name="includes">The includes.</param>
 105:     /// <returns>Returns the first element of a sequence, or a default value if the sequence
 106:     /// contains no elements.</returns>
 107:     public ConcreteType FirstOrDefault(Expression<Func<ConcreteType, bool>> predicate, params string[] includes)
 108:     {
 109:         return GetObjectSet(includes).FirstOrDefault(predicate);
 110:     }
 111:  
 112:     /// <summary>
 113:     /// The single element of the input sequence
 114:     /// </summary>
 115:     /// <param name="predicate">The predicate.</param>
 116:     /// <param name="includes">The includes.</param>
 117:     /// <returns>The single element of the input sequence.</returns>
 118:     public ConcreteType Single(Expression<Func<ConcreteType, bool>> predicate, params string[] includes)
 119:     {
 120:         return GetObjectSet(includes).Single(predicate);
 121:     }
 122:  
 123:     /// <summary>
 124:     /// Gets a collection of all persisted items that pass the test in the predicate
 125:     /// </summary>
 126:     /// <param name="predicate">The predicate.</param>
 127:     /// <param name="includes">The includes.</param>
 128:     /// <returns>Collection of all persisted items that pass the test in the predicate</returns>
 129:     public IList<ConcreteType> Find(Expression<Func<ConcreteType, bool>> predicate, params string[] includes)
 130:     {
 131:         return GetObjectSet(includes).Where(predicate).ToList();
 132:     }
 133:  
 134:     /// <summary>
 135:     /// Gets a collection of all persisted items
 136:     /// </summary>
 137:     /// <param name="includes">Sub-entities to include.</param>
 138:     /// <returns>Collection of all persisted items</returns>
 139:     public virtual IList<ConcreteType> FindAll(params string[] includes)
 140:     {
 141:         return GetObjectSet(includes).ToList();
 142:     }
 143:  
 144:     /// <summary>
 145:     /// Applies the changes for a single entity to the context
 146:     /// </summary>
 147:     /// <param name="toSave">Modified entity to apply changes for.</param>
 148:     public virtual void ApplyChanges(ConcreteType toSave)
 149:     {
 150:         ValidateAggregate(toSave);
 151:  
 152:         ApplyToContext(toSave);
 153:  
 154:         // if no current transaction, then save, otherwise it belongs to the unit of work scope
 155:         if (TransactionManager == null || TransactionManager.CurrentContext == null)
 156:         {
 157:             GetObjectSet().Context.SaveChanges();
 158:         }
 159:     }
 160:  
 161:     /// <summary> Applies the changes for a collection of entities to the context
 162:     /// </summary>
 163:     /// <param name="toSave">Collection of modified entities to apply changes for.</param>
 164:     public virtual void ApplyChanges(IEnumerable<ConcreteType> toSave)
 165:     {
 166:         foreach (var item in toSave)
 167:         {
 168:             ValidateAggregate(item);
 169:  
 170:             ApplyToContext(item);
 171:         }
 172:  
 173:         // if no current transaction, then save, otherwise it belongs to the unit of work scope
 174:         if (TransactionManager == null || TransactionManager.CurrentContext == null)
 175:         {
 176:             GetObjectSet().Context.SaveChanges();
 177:         }
 178:     }
 179:  
 180:     /// <summary>
 181:     /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
 182:     /// </summary>
 183:     public void Dispose()
 184:     {
 185:         this.Dispose(true);
 186:         GC.SuppressFinalize(this);
 187:     }
 188:  
 189:     /// <summary>
 190:     /// Refreshes the specified entities from the data store.
 191:     /// </summary>
 192:     /// <param name="entities">The entities.</param>
 193:     public void Refresh(params ConcreteType[] entities)
 194:     {
 195:         CurrentObjectSet.Context.Refresh(RefreshMode.StoreWins, entities);
 196:     }
 197:  
 198:     /// <summary>
 199:     /// Validates the specified record to save and throws ValidationException if condition is not met
 200:     /// </summary>
 201:     /// <param name="toSave">The record to save.</param>
 202:     protected virtual void ValidateAggregate(ConcreteType toSave)
 203:     {
 204:         // no default implementation
 205:     }
 206:  
 207:     /// <summary>
 208:     /// Gets the object set.
 209:     /// </summary>
 210:     /// <param name="includes">The includes.</param>
 211:     /// <returns>
 212:     /// Object set with the specified dependent objects included.
 213:     /// </returns>
 214:     protected ObjectQuery<ConcreteType> GetObjectSet(params string[] includes)
 215:     {
 216:         var objectSet = CurrentObjectSet.OfType<ConcreteType>();
 217:         foreach (var include in includes)
 218:         {
 219:             objectSet = objectSet.Include(include);
 220:         }
 221:  
 222:         return objectSet;
 223:     }
 224:  
 225:     /// <summary>
 226:     /// Applies changes for the given entity to context.
 227:     /// </summary>
 228:     /// <param name="entityToSave">The entity to save.</param>
 229:     protected void ApplyToContext(ConcreteType entityToSave)
 230:     {
 231:         // If the object toSave was an existing record loaded from the same context that we are attempting to save it back to 
 232:         // then some special considerations are needed.
 233:         ObjectStateEntry entityStateEntry;
 234:         if (CurrentObjectSet.Context.ObjectStateManager.TryGetObjectStateEntry(entityToSave, out entityStateEntry))
 235:         {
 236:             object contextEntity = entityStateEntry.Entity;
 237:  
 238:             if (entityToSave.ChangeTracker.State == ObjectState.Deleted)
 239:             {
 240:                 // it's possible to have a different reference to the same entity (entity keys are the same). This will cause an error
 241:                 // when trying to delete, so we need to make sure that we are deleting the entity that is already in the store.
 242:                 CurrentObjectSet.Context.ObjectStateManager.ChangeObjectState(contextEntity, EntityState.Deleted);
 243:             }
 244:             else if (entityToSave.ChangeTracker.State == ObjectState.Modified)
 245:             {
 246:                 // if the entity already in the store is not the same reference as the entity we are trying to save (even though they represent the same record in the store)
 247:                 // we need to move the changes over to the record already in the store. If they are the same, the changes are already there.                        
 248:                 if (!object.ReferenceEquals(contextEntity, entityToSave))
 249:                 {
 250:                     CurrentObjectSet.Context.ApplyCurrentValues(CurrentObjectSet.EntitySet.Name, entityToSave);
 251:                 }
 252:             }
 253:         }
 254:         else
 255:         {
 256:             // Apply changes only works when the object toSave does not already have a reference in the context's ObjectStateManager
 257:             CurrentObjectSet.ApplyChanges(entityToSave);
 258:         }
 259:     }
 260:  
 261:     /// <summary>
 262:     /// Releases unmanaged and - optionally - managed resources
 263:     /// </summary>
 264:     /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
 265:     private void Dispose(bool disposing)
 266:     {
 267:         if (disposed)
 268:         {
 269:             return;
 270:         }
 271:  
 272:         if (disposing)
 273:         {
 274:             if (localContext != null)
 275:             {
 276:                 localContext.Dispose();
 277:             }
 278:         }
 279:  
 280:         disposed = true;
 281:     }
 282: }

That’s it. Next time we’ll look at the Unit of Work Pattern implementation that I came up with which is a bit more involved than the Repository.

Tags: ,

Programming

Transpose Lines, Words and Characters - Visual Studio Hotkey

by Mark Shiffer 8. April 2010 15:09

Alt-Shift-T – Transpose two lines

Ctrl-Shift-T – Transpose two words

Ctrl-T – Transpose two characters

Tags:

Programming | Shortcuts

Automated WPF UI Tests Using White

by mark shiffer 1. February 2010 16:16

Ran across a CodePlex project today that seems to have some merit. Although it is in the early stages of development, ThoughtWorks’ (Martin Fowler, et. la.) project "White"looks promising and has received some good reviews. A few blurbs from their site explaining the product:

White supports all rich client applications, which are Win32, WinForm, WPF and SWT (java). It is .NET based and hence you wouldn't have use proprietary scripting language. You can use your favourite .NET language, IDE and tools for developing tests/automation programs.
White provides consistent object oriented API for all kinds of applications. Also it hides all the complexity of Microsoft's UIAutomation library and windows messages (on which it is based).

Third Party Controls
White works on top of UIAutomation framework of .Net. If you intend to or have third party controls in your application, you should verify whether they these controls are supported by UIA. You can use UIAutomationVerify http://www.codeplex.com/UIAutomationVerify to check this. When any controls is supported the tool would show you the inner details of the control in a tree form.


Silverlight Versions
White's released version doesn't support silverlight 3.0 yet, it support Silverlight 2.0. Although if you checkout the source code from trunk then it would work for Silverlight 3 as well.


64 Bit Windows
White is currently not tested on 64-bit windows, so you might face issues with it.


Would white support my application and controls inside it? (.....as I am not using standard .NET application)
White does support Win32, WPF, WinForm, SWT and Silverlight applications. In fact SWT is a type of Win32 application when running on windows. Powerbuilder, MFC, etc applications are all Win32 applications as well. In order to determine which controls are automatable, please use UISpy or UIAutomationVerify to check whether these controls are visible using MS UIAutomation. White is based on UIAutomation framework.

Tags:

Research | Programming

Static Type Initialization in .NET 4.0

by mark shiffer 1. February 2010 15:56

Jon Skeet has a rather interesting article over on his blog called "Type initialization changes in .NET 4.0". In it he explains through example how static methods and variables affect the timing of when the type gets initialized. Essentially, in 3.5, as soon as you hit a reference to a type it is initialized. This is not the case with 4.0. The CLR is more intelligent now and only initializes the type once static member variables are referenced. So, if you have a static method on a type that is fully encapsulated, the method can be called without the type being initialized.

Tags:

Programming | Research

Performance Terminology

by mark shiffer 20. January 2010 16:15

Read an article over on Parallel Programmingthat gave some good definitions for common terms. So I am reprinting it here.

All of these terms are overloaded, even in the context of parallel computing. However, we’ve used them extensively to describe how well our parallel algorithms and demo applications work. And sometimes, we throw them around carelessly on the blog, forums, etc., so here are our general definitions.

Performance is an attribute that refers to the total elapsed time of an algorithm’s execution.  Less elapsed time means higher performance.

Speedup is a metric that quantifies performance by comparing two elapsed time values.  In parallel computing, these two values are usually generated by the execution of a serial algorithm and a parallelized version of the same algorithm.  Speedup is then calculated using the following equation:

Speedup = Serial Execution Time / Parallel Execution Time

So if a serial algorithm takes 100 seconds to complete, and the parallel version takes 40 seconds, the speedup is “2.5x”.

Efficiency is a metric that builds on top of speedup by adding awareness of the underlying hardware.  It is usually calculated using the following equation:

Efficiency = Speedup / # of cores

So if speedup is “2.5x” on a 4-core machine, efficiency is 0.625 or 62.5%.

Scalability is an attribute that refers to the speedup of an algorithm given different numbers of cores/processors.  The efficiency metric is good for quantifying scalability, because if efficiency holds constant as the number of cores changes, we have linear scaling (or awesome scalability).

Tags:

Programming | Research

DSL Starting Points (Domain Specific Language)

by mark shiffer 2. November 2009 21:49

I’ve been throwing around the idea of creating a DSL for a few different areas here at work for a while now. I came across a decent list of parsing engines that might help with that. I putting it here for future reference:

  1. http://irony.codeplex.com/
  2. http://antlrcsharp.codeplex.com
  3. http://csparser.codeplex.com
  4. http://expressioneval.codeplex.com
  5. http://flee.codeplex.com
  6. http://ilcalc.codeplex.com
  7. http://lazyparser.codeplex.com
  8. http://linqovercsharp.codeplex.com
  9. http://ncalc.codeplex.com
  10. http://simpleexpressioneval.codeplex.com
  11. http://simplemathparser.codeplex.com

Tags:

Research | Programming

Copyright © 2001-2012 MS Consulting, Inc. All Rights Reserved.