Sunday, March 13, 2011

The Repository Pattern with EF Code First & MEF

[Edit: new post with demo on the subject http://average-uffe.blogspot.com/2011/06/t4scaffolding-complete-system-from.html]
In this post I will show you how I implement a generic repository pattern with EF Code First as dataprovider, and MEF as the provider for separation of concern.
This post will be quite long since all the source code will be exposed…
If you never heard about MEF, check my previous post for a brief intro http://average-uffe.blogspot.com/2010/10/managed-extensibility-framework.html

A RoadMap (the steps in this tutorial/post…)

  • Pre req´s
  • Setup the solution
  • Create a simple domainmodel (Person and Cars will do).
  • Create data and service interfaces (generic and entity-interfaces).
  • Implement the geneic repository and the EFCodeFirst DBContext (and entity-repositorys).
  • Create our class for handling MEF imports. 
  • Implementing the generic ServiceInterfaces and import the exported repository with MEF (and entity-services).
  • What have we created? An architectual overview!
  • What´s next?

Pre Req´s

  • Visual Studio 2010 (Sp1 beta atleast).
  • SqlExpress.

Setup the solution

Create 5 projects… 4 Class Library project and one MVC3 WebApp… install MVC if needed.
The classlibraries will represent Core (the domainmodel), Data (the repository), Services (the implementation of serviceinterfaces) and Common for some utilities….
Xlent.Demo.SolutionArch
The Data-project will export interfaces so we setup a postbuild event in Visual Studio to copy the dll to our pluginfolder.
postbuildevents
Run Nuget PackageManager on Core and Data-projects for EFCodeFirst (run the command twice.. one for Core and one for Data).
install-package codefirst

Create a simple domainmodel

Finally some coding LerWe will create three POCO classes. One abstract baseclass for common properties such as key, createdTime and updatedTime. And then our Person and Car classes that will inherit the abstract baseclass.
[DataContract]
public abstract class PersistentEntity
{
   
[DataMember]
   
[Key]
   
public int Id { get; protected set; }

   
[DataMember]
   
public DateTime Created { get; set; }

   
[DataMember]
   
public DateTime Updated { get; set; }
}
[DataContract]
public class Car : PersistentEntity
{
   
[DataMember]
   
[StringLength(15)]
   
public string Color { get; set; }

   
[DataMember]
   
[StringLength(10)]
   
public string RegNr { get; set; }

   
[DataMember]
   
[StringLength(20)]
   
public string Brand { get; set; }

   
[DataMember]
   
public virtual Person Owner { get; set; }
}
[DataContract]
public class Person : PersistentEntity
{
   
[DataMember]
   
[StringLength(50)]
   
public string FirstName { get; set; }

   
[DataMember]
   
[StringLength(50)]
   
public string LastName { get; set; }

   
[DataMember]
   
[StringLength(12)]
   
public string SSN { get; set; }
        
   
[DataMember]
   
public DateTime Birthdate { get; set; }

   
[DataMember]
   
public virtual IList<Car> Cars { get; set; }
}

Create Data & Service-Interfaces

Above we created the simple domainmodel and now we will create the interfaces for the repository and the service. To understand the reason to why we need interfaces is important! The interfaces data and service may very well have the same signature, but we will need them both to separate and hide the datainterfaces from being exposed further than to the servicelayer. Since we are using MEF the interfaces is also important because we tell MEF that we export the interface (and also that we want to import anything that implements a certain interface).
We will have baseinterfaces for both data and service by using Generics.

The RepositoryInterface

public interface IRepository<T>
{
   
IEnumerable<T> GetAll();
   
T GetById(int id);
   
int SaveOrUpdate(T entity);
   
bool Delete(T entity);
}
Above we defined the basic CRUD operations for all entities.. Now we have a very simple implementation of the entities in our domainmodel, displayed below.
Definition for the domainmodels datainterfaces
interface IPersonRepository : IRepository<Person>
{
}
interface ICarRepository : IRepository<Car>
{
}
Thats it… Now we will do the same thing for the serviceinterfaces…

The ServiceInterface

public interface IService<T>
{
   
IEnumerable<T> GetAll();
   
T GetById(int id);
   
int SaveOrUpdate(T entity);
   
bool Delete(T entity);
}
public interface ICarService : IService<Car>
{
}
public interface IPersonService : IService<Person>
{
}

Implement the geneic repository and the EFCodeFirst DBContext

In our Data-project we will implement the repositoryinterfaces that we created in the Core-project. We start with the baserepository.
To start, we only create the abstract class called baserepository and implemt the stubs for IRepository<T> (shown below)

public abstract class BaseRepository<T> : IRepository<T> where T : PersistentEntity
{
   
public IEnumerable<T> GetAll()
   
{
       
throw new NotImplementedException();
   
}
   
public T GetById(int id)
   
{
       
throw new NotImplementedException();
   
}
   
public int SaveOrUpdate(T entity)
   
{
       
throw new NotImplementedException();
   
}
   
public bool Delete(T entity)
   
{
       
throw new NotImplementedException();
   
}
}
Nothing existing in that class… Since we want to use EFCodeFirst we now need to tell our repository how to handle the CRUD operations. To start we add a new class (DemoContext) that implements the DBContext. This is the class that will tell EFCodeFirst what entities to include in the mapping.
public class DemoContext : DbContext
{
   
public DbSet<Person> Companies { get; set; }
   
public DbSet<Car> Employments { get; set; }

   
public DemoContext() : base("XlentDemoDB")
   
{        
       
//DropAndReCreate if in debug and model is changed.
        if (System.Diagnostics.Debugger.IsAttached)
           
DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<DemoContext>());
   
}
        
   
public ObjectContext ObjectContext()
   
{
       
return ((IObjectContextAdapter)this).ObjectContext;
   
}
}
Now we have a context to work with… Lets use it in our repository… And that will give us a new verison of the stubb of the repository above.
Repository Implementing our DbContext
Okay, this is alot of code in a post but this is the biggest class in this example… And quite important to… This handles all CRUD operations regardless of the entity as long as the entity inherits the “PersistentEntity” class. Note that we use the export attribut to expose the class to MEF.
[Export(typeof(IRepository<>))]
public abstract class BaseRepository<T> : IRepository<T> where T : PersistentEntity
{
   
protected DemoContext Ctx;
   
protected string EntitySetName { get; set; }
   
protected string ContainerName { get; set; }
   
protected ObjectContext ObjectContext { get; set; }
   
protected Type CurrentType { get; set; }

   
protected BaseRepository()
   
{
       
//Setup context
        this.Ctx = new DemoContext();

       
//Get The ObjectContext to be able to work with generics.
        this.ObjectContext = this.Ctx.ObjectContext();

       
//Attach the SavingChanges event.
        this.ObjectContext.SavingChanges += (sender, e) => BeforeSave(this.GetChangedOrNewEntities());

       
//Get EntityName and ContainerName
        this.EntitySetName = this.ObjectContext.CreateObjectSet<T>().EntitySet.Name;
       
this.CurrentType = typeof(T);
   
}

   
private IEnumerable<PersistentEntity> GetChangedOrNewEntities()
   
{
       
const EntityState newOrModified = EntityState.Added | EntityState.Modified;
       
return this.ObjectContext.ObjectStateManager.GetObjectStateEntries(newOrModified)
           
.Where(x => x.Entity != null).Select(x => x.Entity as PersistentEntity);
   
}

   
public void BeforeSave(IEnumerable<PersistentEntity> entities)
   
{
       
foreach (var entity in entities)
       
{
           
entity.Updated = DateTime.Now;
           
entity.Created = !IsPersistent(entity) ? DateTime.Now : entity.Created;
       
}
   
}

   
private static bool IsPersistent(PersistentEntity entity)
   
{
       
return entity.Id != 0;
   
}

   
public virtual int SaveOrUpdate(T entity)
   
{
       
if (IsPersistent(entity))
           
this.Ctx.Set(this.CurrentType).Attach(entity);            
       
else
           
this.Ctx.Set(typeof(T)).Add(entity);            

       
return this.Ctx.SaveChanges();
   
}

   
public virtual T GetById(int id)
   
{
       
return this.Ctx.Set(this.CurrentType).Find(id) as T; 
   
}

   
public virtual IEnumerable<T> GetAll()
   
{
       
return this.ObjectContext.CreateObjectSet<T>(this.EntitySetName);
   
}
    public virtual bool Delete(T entity)
   
{
       
try
       
{
           
this.Ctx.Set(this.CurrentType).Remove(entity);
           
return true;
       
}
       
catch
       
{
           
return false;
       
}
   
}
}
Now that we have the baserepository in place we can create really simple Repositorys for our Person and Car entities…
The PersonRepository
[Export(typeof(IPersonRepository))]
public class PersonRepository : BaseRepository<Person>, IPersonRepository
{        
}
[Export(typeof(ICarRepository))]
public class CarRepository : BaseRepository<Car>, ICarRepository
{
}
If needed you can override the baseclass methods in teh implementations since the baseclass methods is virtual…

Create our class for handling MEF imports

In our repository we export interfaces, and in the servicelayer we want to import the exports… To be able to do this we will write a class that looks for exports in a predefined catalog (remember the postbuild event that copies the dll to our plugin catalog?)… We call the MEF class for Composable and make it abstract…
public abstract class Composable
{
   
protected CompositionContainer CompositionContainer { get; set; }
   
protected AggregateCatalog AggregateCatalog { get; set; }
   
protected IList<string> DirectoryCatalogs { get; set; }

   
protected Composable()
   
{
       
this.DirectoryCatalogs = new List<string>();

       
this.AggregateCatalog = new AggregateCatalog();

       
//Create the catalog to look for plugins in...
        this.AddDirectoryCatalog(ConfigurationManager.AppSettings.Get("MefDirectoryCatalog"));

       
//Add the catalog to the hostcatalog...                        
        this.Compose();
   
}

   
protected void AddDirectoryCatalog(string catalog)
   
{
       
this.DirectoryCatalogs.Add(catalog);
   
}

   
public void Compose()
   
{
       
//Add Catalogs
        foreach (var directoryCatalog in this.DirectoryCatalogs)
       
{
           
this.AggregateCatalog.Catalogs.Add(new DirectoryCatalog(directoryCatalog));
       
}

       
//Create compositioncontainer catalog export/import.
        this.CompositionContainer = new CompositionContainer(this.AggregateCatalog);

       
//And... Compose it... :)              
        this.CompositionContainer.ComposeParts(this);
   
}
}
No need to say more about this class than that it will need a config-appsetting with the key “MefDirectoryCatalog” that points to the plugincatalog described in the beginning of the post.

Implementing the generic ServiceInterfaces and import the exported repository with MEF

We do not want a project or dll referens to our datalayer from our servicelayer… This is where MEF does it´s magic. Since we export the repository interfaces we will tell our service to import the interfaces… In that way we do not need to reference the actuall datalayer but only the domainmodel in the Core project…. This gives us a plugable architecture and we can replace EFCodeFirst with a xml repository if we want… As long as the repository implements and exports the interfaces!!!
The BaseService
Just like the BaseRepository we will have a generic abstract class for all services… Although much simpler than the repository class.
public abstract class BaseService<T> : Composable, IService<T> where T : PersistentEntity
{
   
//MEF does not allow import on open generics.
    //Workaround by setting this in Ctor of implementing classes.
    //[Import(typeof(IRepository<>))]        
    protected IRepository<T> Repository;

   
public virtual IEnumerable<T> GetAll()
   
{
       
return this.Repository.GetAll();
   
}

   
public virtual T GetById(int id)
   
{
       
return this.Repository.GetById(id);
   
}

   
public virtual int SaveOrUpdate(T entity)
   
{
       
return this.Repository.SaveOrUpdate(entity);
   
}

   
public virtual bool Delete(T entity)
   
{
       
return this.Repository.Delete(entity);
   
}
}
Thats our baseservice hiding the repository… The servicelayer would be the place to add bussineslogic, would probably be done in the classes that inherit baseservice.
Now we add PersonService and CarService…
public class PersonService : BaseService<Person>, IPersonService
{
   
[Import(typeof(IPersonRepository))]
   
protected new IPersonRepository Repository;

   
public PersonService()
   
{
       
base.Repository = this.Repository;
   
}
}
public class CarService : BaseService<Car>, ICarService
{
   
[Import(typeof(ICarRepository))]
   
protected new ICarRepository Repository;

   
public CarService()
   
{
       
base.Repository = this.Repository;
   
}
}
Just as the BaseRepository the BaseService has virtual methods if you want to override to do some specific logic…

What have we created? An architectual overview!

Ok… I just want to show the loosely coupled architecture of this solution… All made possible by MEF
ArchOverView
As you can see the Service-assmebly has no clue about the Data-assembly, the both just know about the Core and the Interfaces that they implement and export.

What´s next?

My idea was to also export the service interface and import the interfaces from a MVC controller, but I think this is to long already (have you been reading all this Skrattar)… So if someone want´s me to I´ll write a second post about howto put MVC on top of this and then create a REST api in MVC and use JQuery in some simple examples.
To be continued….

[EDIT 11-05-08] new post on the subject. Contains video and VSIX solutiontemplate. 

_______________________________________________________
Thanks for reading
Regards
Uffe

29 comments:

  1. This is a nice article..
    Its very easy to understand ..
    And this article is using to learn something about it..

    c#, dot.net, php tutorial

    Thanks a lot..!

    ReplyDelete
  2. What is composable in the base service class?

    ReplyDelete
  3. rw: Hi there. I suppose that your question is why I inherit the Composable class in BaseService when there is no [Import] in BaseService? If so, the answer is that all classes/services that inherit BaseService has imports to satisfy IRepository (or the interface for example IPersonRepository)... So thats why the baseclass takes care of it...

    Ex: [Import(typeof(IPersonRepository))]
    protected new IPersonRepository Repository;

    If your question was "what is composable?" as in what class is it.. (but I do not think that was the question) you can see the class above BaseService.

    Regards
    Uffe

    ReplyDelete
  4. Article is a interesting. Good job. I hope soon see example

    ReplyDelete
  5. I Uffe hi!
    I have little question. What do you say about create Context class how container and Entities how plug-in? It is possibly?

    ReplyDelete
  6. Hello Программист (programmer) :).
    I´m not sure I follow you here... but please email me at codeplanner at gmail.com and describe what it is you want to achive. Everything is possible ;), but if you want to have plugins into the EF Context I think it will be hard.. Thought of it myself.

    I´ll have been some changes in the code recently and will post a new version soon.

    ReplyDelete
  7. Hi Uffe. Thank you for answer. My name is Gragoryy or Greg. Yes I want plugins into the EF Context. But you're a right, it is hard.
    But I have two question now.
    First Why you used ObjectContext class in
    public ObjectContext ObjectContext()
    {
    return ((IObjectContextAdapter)this).ObjectContext;
    }

    And what you say about if used template int DemoContext?

    public class DemoContext : DbContext where T : PersistentEntity

    ReplyDelete
  8. Nice article ...waiting for update! :)

    ReplyDelete
  9. Looking forward to download the demo of this very interesting project, especially to see how all this is going to glue to MVC. Thanks

    ReplyDelete
  10. Sorry for the delay in the demo.. My dayjob is slowing me down ;)
    But you can download a VSIX (template) to get the project (so far) up and running. See the readme in the mvc project for info on howto get it running.
    It has Scaffolding for entities and all repositories, services (it works but can be much improved) Link to template: http://bit.ly/mdHMgH

    ReplyDelete
  11. Uffe you check what data save? Because I have problem in save date. Data only add, but update not work.

    ReplyDelete
  12. public int Id { get; protected set; }

    change to

    public int Id { get; set; }

    Because Id all time only 0 :)

    And I do no know why. But code
    this.Ctx.Set(this.CurrentType).Attach(entity);
    data not save in DB

    ReplyDelete
  13. I found how fix. The problem is that in new version EF 4.1 for change you must uset type EntityState and other use method

    public virtual int SaveOrUpdate(T entity)
    {
    if (IsPersistent(entity))
    this.Ctx.Entry(entity).State = EntityState.Modified;
    else
    this.Ctx.Entry(entity).State = EntityState.Added;

    return this.Ctx.SaveChanges();
    }

    ReplyDelete
  14. Hello Greg.
    You are rigth that there are some issues in the baserepository. I´ve made some changes since this post was released. Great that you´ve found a solution for your problem. My saveorupdate work however it´s now loking like this
    public virtual int SaveOrUpdate(T entity)
    {
    if (IsPersistent(entity) && this.Ctx.Entry(entity).State == EntityState.Modified)
    {
    var internalEntity = this.Ctx.Set().Find(entity.Id); entity.Updated = DateTime.Now; this.Ctx.Entry(internalEntity).CurrentValues.SetValues(entity);
    }
    else
    this.Ctx.Set().Add(entity);

    this.Ctx.SaveChanges();
    return entity.Id;
    }

    Will post a valid link to the template and a video showing a quick turorial this weekend.

    Regards
    Uffe

    ReplyDelete
  15. Greg... One more thing though. Do not remove the protected set on the primary key. It´s supposed to be protected so that only the repository can edit the value of the primary key! This is really important!

    Will look into to your SaveOrUpdate, maybe I can use that instead.

    ReplyDelete
  16. Uffe hi. I glad what I can help you.
    But you wrong about protection property. If not do this, property Id all have 0

    ReplyDelete
  17. I am designing a similar solution with an extensible DAL-like Host. I have a few questions. Primarily, your library structure is different than what I've experienced. If I can determine how your structure relates to mine, I think I will be able to understand more of what you are doing. I have been trying to create my architecture on the basis of a shared library containing interfaces, etc.; the entity library (object context, POCO entities); and the Host/DAL. The Host then has the ability to provide the Business Logic Layer access to multiple contexts - e.g., an extensible data service provider. It seems that my problem exists in the BLL's ability to resolve a POCO entity. The POCO entities reside on the backend of the Host; and the enitity library cannot be referenced to resolve the POCO entity types. Is it likely that the architecture you demonstrate will assist in resolving this issue?

    ReplyDelete
  18. Hi Greg.
    If your Id property is always 0 I´m afraid you´re doing something wrong :( My version works. And I´ve posted a video-demo and also the vsix template used in the video.
    Maybe you can find the differences in the template?
    Regards
    Uffe

    ReplyDelete
  19. Hello D
    I think I understand your problem, the way I see it my "Core" assembly will contain the domainmodel and also interfaces for data and services (a.k.a contracts). The BLL will have to have a reference to the Core (domainmodel). How are you going to perform BLL without the entity? Maybe I´m not understanding your problem correctly. As I said to greg: Try the template in my new post and watch the video. Maybe it will do it (and maybe not). Good Luck

    Regards
    Uffe

    ReplyDelete
  20. You are correct, this has been the issue - how will my BLL work without referencing the POCO entity objects? I have simply been attempting different methods to see if it possible for the BLL to pass a query function (Func<> Predicate) to my repository class for execution. I believe I will have to split my entity library so the Context is on the backend of the Host and the POCO entity objects in a separate library. I had hoped there would be a way for me to inject the Host repository mechanism with the POCO objects once the entity library is discovered using MEF.

    ReplyDelete
  21. Ok. Interesting thoughts!!! Your BLL have to be aware of the entities, but there is no need for BLL to know about the context. You should always be able to replace your context without replacing anything else. It´s the interfaces that make this possible. Look at the demo and download the template in my latest post to see what I mean. You could have a generic BLL that passes the entities to the context.. But the question is then why have a BLL? And the context need to know of the entities at compiletime (when using entityframework). If you have a XML-repository (or similar) you could have unknown types and add them at runtime. It would be fun to try your idea though... Do post a note here if you find a solution. MEF is great and we use it in our websocketserver for plugin-functionality.

    ReplyDelete
  22. Uffe hi! Maybe I not correct to write. When I get data from db Id not. But when I get data from page for edit Id = 0

    ReplyDelete
  23. Hi greg. If thats the case i suspect that you have a problem in your view or actionmethod. Download the template and follow the video and it should work.
    Regards
    uffe

    ReplyDelete
  24. Hi .
    I use mef in my asp.net application to make it plug-able.I have DAL which is created using Entity Framework CFT, I want every plug-in to use this DAL, but as you know every time the model changes, CFT need to re-create the database, I mean imagine I have created a Forum plug-in and it is obvious that it needs some tables and entities to work fine, But adding new entity to my DbContext Class would cause re-creation of database, Is there any way yo avoid it ?

    ReplyDelete
  25. well done !
    I wish a was able to apply this with MEF but i finally ended with Spring.Net!
    however, your implementation of repository pattern is the best i came across so far.

    ReplyDelete
  26. I actually hate the idea of one to one relation of an entity with repository and service. Like Person, PersonRepository and PersonService. Cheap design. I think we should have something like this http://www.asifashraf.com/search/?q=repository and for service, one service should cover one domain logic which can contact to a group of related tables.

    ReplyDelete
  27. public interface IRepository[T] : IDisposable where T : class
    {
    /// [summary]
    /// Gets all objects from database
    /// [/summary]
    IQueryable[T] All();

    /// [summary]
    /// Gets objects from database by filter.
    /// [/summary]
    /// [param name="predicate"]Specified a filter[/param]
    IQueryable[T] Filter(Expression[Func[T, bool]] predicate);

    /// [summary]
    /// Gets objects from database with filting and paging.
    /// [/summary]
    /// [typeparam name="Key"][/typeparam]
    /// [param name="filter"]Specified a filter[/param]
    /// [param name="total"]Returns the total records count of the filter.[/param]
    /// [param name="index"]Specified the page index.[/param]
    /// [param name="size"]Specified the page size[/param]
    IQueryable[T] Filter(Expression[Func[T, bool]] filter, out int total, int index = 0, int size = 50);

    /// [summary]
    /// Gets the object(s) is exists in database by specified filter.
    /// [/summary]
    /// [param name="predicate"]Specified the filter expression[/param]
    bool Contains(Expression[Func[T, bool]] predicate);

    /// [summary]
    /// Find object by keys.
    /// [/summary]
    /// [param name="keys"]Specified the search keys.[/param]
    T Find(params object[] keys);

    /// [summary]
    /// Find object by specified expression.
    /// [/summary]
    /// [param name="predicate"][/param]
    T Find(Expression[Func[T, bool]] predicate);

    /// [summary]
    /// Create a new object to database.
    /// [/summary]
    /// [param name="t"]Specified a new object to create.[/param]
    T Create(T t);

    /// [summary]
    /// Delete the object from database.
    /// [/summary]
    /// [param name="t"]Specified a existing object to delete.[/param]
    int Delete(T t);

    /// [summary]
    /// Delete objects from database by specified filter expression.
    /// [/summary]
    /// [param name="predicate"][/param]
    int Delete(Expression[Func[T, bool]] predicate);

    /// [summary]
    /// Update object changes and save to database.
    /// [/summary]
    /// [param name="t"]Specified the object to save.[/param]
    int Update(T t);

    /// [summary]
    /// Get the total objects count.
    /// [/summary]
    int Count { get; }
    }

    ReplyDelete
  28. Muhammad Asif:
    Ok, if that works for you, then... good for you :)

    ReplyDelete