Build enterprise application with WPF, WCF, Entity Framework and Prism. Tutorial 02.

Update: source code and documentation are now available on CodePlex at this address: http://prismtutorial.codeplex.com/

Build a generic repository with the Entity Framework.

In the previous series of articles about M-V-VM we used the AdventureWorks database, available on CodePlex.
After this article (configure a data layer with LinQ-to-SQL) I have got some reader’s emails asking me this and that. So, I am going to give you all those answers right now.

Download and configure the Adventure Works database.

On my dev PC I have SQL Server 2008 Standard version, but this tutorial is working also with the express or any other version.

  1. Go to CodePlex Adventure Works web site project and download the AW available version (light and full). I have downloaded the package called ”Adventure Works All Databases”.
  2. Go into the folder tree Tools/Samples and you will find the .mdf and .ldf and also the T-SQL script if you want to run it from a prompt command line.
  3. Open your SSMS and from the master database, install the version that you prefer. My samples work with both version, as I use always the Adventure Works LT (Light version).

image

  1. Mandatory: as I use Windows Authentication in all my samples, you must fix that in your local Db and change the connection string in my samples.

Open Visual Studio and create the folder three.

As we are going to work with an enterprise application, in order to simulate the 3 tiers, I have created 3 solution folders, one for the data service, one for the client part and one for the test. We will expand these folders during the building process.

The initial solution three will be:

imageSolution name: PrismTutorial
DataLayer: PrismTutorial.DataLayer
  TDD: Test.DataLayer
Consuming Service: PrismTutorial.WCF

Working with Entity Framework.

In the first series of tutorials, we used LinQ-to-SQL because:

  • It’s easier, It’s faster, It uses the relation 1 to 1 with the database tables and so on.

For this tutorial we are going to use the Entity Framework because this one is the real OR/M coming from Microsoft so in an enterprise application it’s better to spend more time and effort on building something stronger and reusable.

Open you VS data layer solution, right click and add an new component, ADO.NET Entity Data Model and configure it to reflect the Adventure Works LT database installed into your machine.

After that VS will show up a entity model designer window very similar to the one that we used with Linq-to-SQL.

imageIf you want to be compliant with my settings, this is how I have configured my Entity Framework:

image

It’s time to play, the Entity Framework repository wrap!

Like any software architect, I try to fit always everything in a more generic, reusable and more readable pattern. If we want to have a reusable UnitOfWork associated with a Repository engine, we must wrap the Entity Framework inside something more generics. Here comes the pain ….

The final result I would like to have is this one:

image

IRepository interface.

First of all we have to define a generic contract (interface) that we will use as our repository. As we want to be generic we need something like this:

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq.Expressions;
  4: 
  5: namespace PrismTutorial.DataLayer {
  6:     public interface IRepository:IDisposable {
  7:         //Add a new Entity
  8:         int Add<T>(T entity);
  9:         //Count the number of entities available
 10:         long Count<T>();
 11:         //Count using a filer
 12:         long Count<T>(Expression<Func<T, bool>> expression);
 13:         //Delete an existing entity
 14:         int Delete<T>(T entity);
 15:         //List all the available entities
 16:         IList<T> GetAll<T>();
 17:         //List the entities using a filter
 18:         IList<T> GetAll<T>(Expression<Func<T, bool>> expression);
 19:         //Get a single entity
 20:         T GetSingle<T>(Expression<Func<T,bool>> expression);
 21:         //Update an existing entity
 22:         int Update<T>(T entity);
 23:     }
 24: }
 25: 

At this point we have a generic implementation of the repository pattern and we do not need to worry about what we are going to save, update or delete.

BaseRepository to handle the dispose of the data context.

The second problem that we have to fix is more related to how the entity framework uses the context in a web application. I have found this article over the web: http://blog.zoolutions.se/post/2009/03/26/Generic-Repository-for-Entity-Framework.aspx, really interesting, so I am going to use the same type of solution.

We need a simple base class that is going to handle the data context and close it if not needed. We can also use the using clause in each method of our repository. I want to use this solution just because it’s more clean and doesn’t force me to write too much code inside the final repository.

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: 
  6: namespace PrismTutorial.DataLayer {
  7:     public abstract class BaseRepository {
  8:         //Our entity framework engine used in the solution
  9:         internal ADVConnection _context;
 10:         //Switch that tells us if the datacontext is reused
 11:         internal bool _contextReused;
 12:         
 13:         //This return the current, or a new connection through the EF
 14:         public ADVConnection GetObjectContext() {
 15:             if (!_contextReused) {
 16:                 return new ADVConnection();
 17:             }
 18:             return _context;
 19:         }
 20: 
 21:         //This is the public method that we will call from our repository
 22:         public void ReleaseObjectContextIfNotReused() {
 23:             if (!_contextReused) {
 24:                 ReleaseObjectContext();
 25:             }
 26:         }
 27: 
 28:         //Simple dispose of the current EF
 29:         public void ReleaseObjectContext() {
 30:             if (_context != null) {
 31:                 _context.Dispose();
 32:             }
 33:             _contextReused = false;
 34:         }
 35:     }
 36: }

Cool, we just need now to wrap all together and play with the data.

The concrete repository.

For the repository pattern there are two implementations, one is to keep everything generic and have 1 repository for the entire domain. The second one is to have a repository for each entity, like UserRepository, ProductRepository, and implement the CRUD operations related to the entity, like AddUser, AddProduct and so on.

I would suggest the second solution only if you need to include some business logic in your CRUD operations or there are some special development requirements. So let’s go for the easier and faster solution, he first one.

In the constructor of our repository we need to pass an instance of the UnitOfWork that in our case is the Entity Framework, like we do with the session with NHibernate.

  1: namespace PrismTutorial.DataLayer {
  2:     public class Repository:BaseRepository,IRepository {
  3: 
  4:         #region Base Implementation
  5: 
  6:         private bool _disposed;
  7:         //Here we pass the connection and we flag the contextReused
  8:         //so we can use the repository with the using clause ...
  9:         public Repository(ADVConnection context) {
 10:             this._context = context;
 11:             this._contextReused = true;
 12:         }
 13: 
 14:         #endregion

Then we have also to implement the IDisposable interface in order to clean-up the connection after each call:

  1:         #region Disposable
  2:         //Dispose implementation
  3:         public void Dispose() {
  4:             DisposeObject(true);
  5:             GC.SuppressFinalize(this);
  6:         }
  7:         //Distructor
  8:         ~Repository() {
  9:             DisposeObject(false);
 10:         }
 11:         //Concrete private implementation of the dispose method
 12:         private void DisposeObject(bool disposing) {
 13:             if (_disposed) {
 14:                 return;
 15:             }
 16:             if (disposing) {
 17:                 if (_context != null) {
 18:                     _context.Dispose();
 19:                 }
 20:                 _disposed = true;
 21:             }
 22:         }
 23:         #endregion

Now we can go ahead and implement each C.R.U.D. method and reflects the changes in the entity framework.

The save method is pretty straightforward, we add an object to our context, using it’s FullTypeName and we persist the changes in the database.

  1:         public int Add<T>(T entity) {
  2:             ADVConnection context = GetObjectContext();
  3:             context.AddObject(typeof(T).Name, entity);
  4:             int result = context.SaveChanges();
  5:             ReleaseObjectContextIfNotReused();
  6:             return result;
  7:         }

Same for the count methods except that we have to create an ObjectQuery that it’s nothing more than a translated query using the T object passed as a parameter.

  1:         public long Count<T>() {
  2:             ADVConnection context = GetObjectContext();
  3:             var query = new ObjectQuery<T>(
  4:                 typeof(T).Name, 
  5:                 context, 
  6:                 MergeOption.NoTracking);
  7:             int count = query.Count();
  8:             ReleaseObjectContextIfNotReused();
  9:             return count;
 10:         }
 11: 
 12:         public long Count<T>(Expression<Func<T, bool>> expression) {
 13:             ADVConnection context = GetObjectContext();
 14:             var query = new ObjectQuery<T>(
 15:                 typeof(T).Name, 
 16:                 context, 
 17:                 MergeOption.NoTracking)
 18:                 .Where(expression);
 19:             int count = query.Count();
 20:             ReleaseObjectContextIfNotReused();
 21:             return count;
 22:         }
 23: 

The only part that you may not know is the parameter MergeOption used in the objectquery constructor. MergeOption has the following values (from the source of the NET Framework) :

  1: namespace System.Data.Objects {
  2:     // Summary:
  3:     //     Specifies how objects being loaded into the object context are merged with
  4:     //     objects already in the object context.
  5:     public enum MergeOption {
  6:         // Summary:
  7:         //     Objects that already exist in the object context are not loaded from the
  8:         //     persisted store. This is the default behavior for queries or when calling
  9:         //     the System.Data.Objects.DataClasses.EntityCollection<TEntity>.Load(System.Data.Objects.MergeOption)
 10:         //     method on an System.Data.Objects.DataClasses.EntityCollection<TEntity>.
 11:         AppendOnly = 0,
 12:         //
 13:         // Summary:
 14:         //     Objects are always loaded from the persisted store. Any property changes
 15:         //     made to objects in the object context are overwritten by the store values.
 16:         OverwriteChanges = 1,
 17:         //
 18:         // Summary:
 19:         //     When an object exists in the object context, it is not loaded from the persisted
 20:         //     store. Any property changes made to objects in the object context are preserved.
 21:         //     This is used to force changes to objects in the object context to save successfully
 22:         //     after an System.Data.OptimisticConcurrencyException has occurred. For more
 23:         //     information, see Saving Changes and Managing Concurrency (Entity Framework).
 24:         PreserveChanges = 2,
 25:         //
 26:         // Summary:
 27:         //     Objects are maintained in a System.Data.EntityState.Detached state and are
 28:         //     not tracked in the System.Data.Objects.ObjectStateManager.
 29:         NoTracking = 3,
 30:     }
 31: }
 32: 

Then we need to implement the delete command. Because we are working on a disconnected environment, first of all we need to get the original object from the repository. Then, we delete it.

  1: public int Delete<T>(T entity) {
  2:     ADVConnection context = GetObjectContext();
  3:     object originalItem;
  4:     EntityKey key = context.CreateEntityKey(typeof(T).Name, entity);
  5:     if(context.TryGetObjectByKey(key, out originalItem)){
  6:         context.DeleteObject(originalItem);
  7:     }
  8:     int result =  context.SaveChanges();
  9:     ReleaseObjectContextIfNotReused();
 10:     return result;
 11: }
 12: 

Now the easy part, GetAll and GetAll using an expression for the criteria.

  1: public IList<T> GetAll<T>() {
  2:     ADVConnection context = GetObjectContext();
  3:     IList<T> list = context
  4:         .CreateQuery<T>(
  5:         "[" + typeof(T).Name + "]")
  6:         .ToList();
  7:     ReleaseObjectContextIfNotReused();
  8:     return list;
  9: }
 10: 

With the criteria:

  1: public IList<T> GetAll<T>(Expression<Func<T, bool>> expression) {
  2:     ADVConnection context = GetObjectContext();
  3:     IList<T> list = context
  4:         .CreateQuery<T>(
  5:         "[" + typeof(T).Name + "]")
  6:         .Where(expression)
  7:         .ToList();
  8:     ReleaseObjectContextIfNotReused();
  9:     return list;
 10: }
 11: 

Just a little note here. If you watch this piece of code:

.CreateQuery<T>(

                “[” + typeof(T).Name + “]”)
here I am using the CreateQuery method to get an ObjectQuery object using the generics. Unfortunately this method requires the name of the entity, so we use Reflection and get the name with the method typeof.

The GetSingle method is the same, we just retreive the FirstOrDefault result of our query:

  1: public T GetSingle<T>(Expression<Func<T, bool>> expression) {
  2:     ADVConnection context = GetObjectContext();
  3:     T result = context
  4:         .CreateQuery<T>(
  5:         "[" + typeof(T).Name + "]")
  6:         .Where(expression)
  7:         .FirstOrDefault();
  8:     ReleaseObjectContextIfNotReused();
  9:     return result;
 10: }
 11: 

And finally, the update method that is going to save the changes we did to an entity.

  1: public int Update<T>(T entity) {
  2:     ADVConnection context = GetObjectContext();
  3:     object originalItem;
  4:     EntityKey key = context.CreateEntityKey(typeof(T).Name, entity);
  5:     if(context.TryGetObjectByKey(key, out originalItem)){
  6:         context.ApplyPropertyChanges(typeof(T).Name,entity);
  7:     }
  8:     int result = context.SaveChanges();
  9:     ReleaseObjectContextIfNotReused();
 10:     return result;
 11: }
 12: 

Like we did with the delete method, first of all we need to retrieve the original instance of the entity, then we simply apply the changes we got from the “working” entity, using the method ApplyPropertyChanges and finally we save everything.

Conclusions.

In this article we saw how to work with the entity framework and build a repository pattern around it. The next step will be to include business and value validation to our entities. We will use the enterprise library 4.1.

Stay tuned!

Tags: