IntroductionA popular pattern for ORM data access is the Repository pattern. Repositories are currently very popular even in EF for the reasons below:
The big disadvantage of EF is rigid architecture which can be hardly mocked so if you want to unit test upper layer you must wrap EF somehow to allow mocking its implementation. The solution I'll show is a very simple implementation of this pattern using EF 4.1 and code first to generate the DataBase. Using the codewe will start using a classic implementation of the Repository Pattern. In this section I'll show a very generic one but you can of course refactor it to be better suitable for your needs. Below the Repository Interface public interface IRepository<TEntity> : IDisposable where TEntity : IEntity { IQueryable<TEntity> GetAll(); void Delete(TEntity entity); void Add(TEntity entity); }
As you can see we got a generic GetAll() method which return an IQuerable that allows to retrieve and query any entity in our model. Because the Repository uses generics we have to constrain it(as you can see the is a TEntity). public interface IEntity { int Id { get; set; } }
Now let's see how to implement the repository pattern. public class Repository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity { private IDbContext _context; public Repository(IDbContext context) { _context = context; } private IDbSet<TEntity> DbSet { get { return _context.Set<TEntity>(); } } public IQueryable<TEntity> GetAll() { return DbSet.AsQueryable(); } public void Delete(TEntity entity) { DbSet.Remove(entity); } public void Add(TEntity entity) { DbSet.Add(entity); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { if (_context != null) { _context.Dispose(); _context = null; } } } }
The repository has a constructor that takes an IDbContext object. That interface add an abstraction layer on the EF DbContext as showed below: public interface IDbContext { IDbSet<TEntity> Set<TEntity>() where TEntity : class; int SaveChanges(); void Dispose(); }
In EF when you are using Code First you need to create a Context which will contain all the DbSet property that is used to access the entities in your model. The context class must inherith from System.Data.EntityDbContext which provides facilities for querying and working with entity data as objects. public class ApplicationContext : DbContext, IDbContext { public DbSet<User> User { get; set; } public new IDbSet<TEntity> Set<TEntity>() where TEntity : class { return base.Set<TEntity>(); } }
The DbContext will contain all the property to access the entity in our context. In this example it will access only "User". In this example we use code first also to generate the DataBase:(only the entity that has got a relative DbSet will be generated) At this point all we need to implement the repository pattern is done.At this point we probably need to create the DataBase using code first approach. public interface IDatabaseInitializer<in TContext> where TContext : IDbContext { // Summary: // Executes the strategy to initialize // the database for the given context. // Parameters: // context: The context. void InitializeDatabase(TContext context); }
This interface is used to create the DataBase and allow the user to specify a kind of strategy. Let's assume we want to delete and create the DataBase every time we only need to implement the interface the specify what we need to do within the InitializeDatabase method as showed below: public class DataBaseInitializer : IDatabaseInitializer<ApplicationContext> { public void InitializeDatabase(ApplicationContext context) { context.Database.Delete(); context.Database.Create(); } }
Now we got all we need. <connectionStrings> <add name="PeluSoft.ApplicationContext" providerName="System.Data.SqlClient" connectionString="Server=myServer;Database=TestUser;Persist Security Info=True;"/> </connectionStrings>
var context=new ApplicationContext();var testDataBaseInitializer = new TestDataBaseInitializer();testDataBaseInitializer.InitializeDatabase(context); Then you can use the repository for the common operation on the entities. var context=new ApplicationContext();var userRepo=new Repository<User>(context);var user =new User() { Username = "TestName" };userRepo.Add(user);context.SaveChanges(); |