Entity Framework POCO, Repository and Specification Pattern [Upgraded to EF 5]

[Updated on Nov 18 2012]: The source code now moved to github @ https://github.com/huyrua/efprs. Let start making pull requests yourself 🙂

I am happy to announce that the framework has been upgraded to target .NET 4.5, Entity Framework 5 and Visual Studio 2012. This post is also a response to someone asking me when should the framework being upgraded to Entity Framework 5.

Some notes regarding this upgrade:

– The source code is now restructured to two versions: one for .Net Framework 4.0, the other one for .Net Framework 4.5. You can access to the source code at http://ef4prs.googlecode.com/svn/trunk/ef4prs-read-only. However, the download page only shows specific versions for you to choose which version that best fits your need.

– Removed repository implementation against ObjectContext, this means the repository is now interfacing mainly with DbContext (not a Lab version anymore). So, if you prefer to work with DbContext, you can get the framework up and running quickly. On the other hand, if you want to work with ObjectContext, this is also easy by upgrading/migrating code from .NET 4.0 version.

That’s it! Not much changes from this upgrade, but that’s a good sign to me since EF 5 does not break some low level code.

Download links http://code.google.com/p/ef4prs/downloads/list

Cheers.

Posted on September 16, 2012, in Entity Framework and tagged . Bookmark the permalink. 62 Comments.

  1. I’ve been following your articles for a while now, great work!

  2. Huyrua, thank you very much for all your effort and for upgrading your code to EF5. I’m following you for improving my projects. Actually I have to implement an abstract generic repository based on your code. Something sort of IGenericRepository and GenericRepositoty where T are the classes generated by a DatabaseFirst EF Model, in order to be able to deal with some CRUD and repetitive catalogs operations within an MVC application and then using some dependency injection for generics, in my case OpenGenerics from Autofac (code.google.com/p/autofac/wiki/OpenGenerics) and save some logic and code. My question is how should I transform both the interface and the concrete class in order to achieve it using Generics? Thank you in advance for your advices.

    • Hey
      I am new for this but i am very interested to get started using this infrastructure.
      The thing is i wanted to use this with the classes generated by db first EF model. In your comment you mentioned some implementation to do that. I wanted to know how you did it.

      my email is sendit_on@yahoo.com

      Thank you in advance!

  3. Have you considered moving your library from code.google.com to github to make it easier for others to submit pull requests?

  4. Thanks for good article. My question is :
    How can I implement IoC container?

  5. How would this code be modified to manage objectcontext lifetime? If you have two instances of a program using this code running on two different computers and each one is making periodic changes to the DB, the caching that is done will prevent the changes that are persisted in the DB from the other program appearing since the cache is read instead of refreshing from the DB.

    If i change the code in:
    public IQueryable GetQuery() where TEntity : class

    to:

    IQueryable ThisQuery = ((IObjectContextAdapter)DbContext).ObjectContext.CreateQuery(entityName);
    System.Data.Objects.ObjectQuery objectQuery = (System.Data.Objects.ObjectQuery)ThisQuery;
    objectQuery.MergeOption = System.Data.Objects.MergeOption.OverwriteChanges;

    return ThisQuery;

    Then the data is ALWAYS refreshed from the DB so any persisted changes by other running copies of the software is read. However with lazy loading enabled if you try to access any information from joined tables the data is still old from the cache.

    I read that you want to keep objectcontext around only as long as you need it, since creating a new one will read all values from the DB. I do not want to do this because if I load an edit form I want the objectcontext around to track the changes through binding that are being made. If I did dispose of the objectcontext then errors are thrown indicating this when the user tries to save their changes on a long running edit form.

    Is there a way to force a complete refresh for all data when running a query and avoid using the cache when lazy loading is enabled?

    Another problem I am running into is that I have one instance of this software running to edit data, and another instance to read data from the DB and populate a text file. If I read the data and populate the text file, then edit the data in the database using my edit instance and save the changes, the second read and populating of the text file will read the original old cached data, unless I close and restart the program. I do not see in the source any method or way of clearing the objectcontext once a generic repository is created, and there is no dispose method on the repository.

    • Dru,

      IMO, this is a concurrency problem, and the solution is out of scope of this data access layer, I think. There have been many solutions to solve this out there. My experience is to use a column, say RevisionNumber for that entity, when one instance save that entity, it’s RevisionNumber is increased, when other instance wants to save the same entity, it should check whether the current RevisionNumber is the same as the one in the database (yes, we might need to load that entity from database again before saving!), if true, then save the entity, otherwise, prompt user that there are changes on the entity from the database and provide some options like: 1) Save and lose any previous change 2) Discard change user make, re-load the data and edit again.

      • Thanks for the reply, I see what you are saying there and it does make sense. I guess my question may not be entirely related to concurrency though.

        Lets go back to just a single instance of an application using this generic repository framework. What I find happens is that once I start up a generic repository accessing a table in the DB that the objectcontext is never cleared for the lifetime of the application. With the dbcontext manager I could not find a way to dispose and start over with a new dbcontext/objectcontext/cache when I am done with a particular dialog.

        I am still looking into it but do you know of anything that can be done so that you can use something like repository.ClearCache to reset the context?

        I see there is:
        DbContextManager.CloseAllDbContexts();
        but this appears to close the connection to the database and does not clear any cache or context.

        I guess it is something to try out but if I call:
        DbContextManager.Current.Dispose();
        or DbContextManager.CurrentFor(“key”).Dispose();
        I wonder if when i try to use the repository it will create a new DbContext automatically, which it looks like the code tries to do, and then this will be a fresh instance with a clear cache.

        I guess the summary of my question is that I am trying to add a way for me to tell the generic repository that I want to close and clear a DbContext and start fresh, like if the user closes an edit screen with a grid and then opens it again. Otherwise the memory usage will just keep climbing since the cache keeps growing as queries are made.

  6. Hi Dru,

    Here’s one idea you can try…

    1. In DbContextManager, add a method like:

    public static void CleanupStorage()
    {
    if (Storage != null) { Storage.Cleanup(); }
    }

    2. And then in DbContextStorage, implement it simply as:

    public void Cleanup() { Storage.Clear(); }

    (As you know, Storage is simply a Dictionary of string, DbContext.)

    3. Or, if you are using WebDbContextStorage, something like:

    if (HttpContext.Current != null) { HttpContext.Current.Items.Remove(StorageKey); }

    4. And finally, in global.asax of your web application, call DbContextManager.CleanupStorage() (the new method above) in the Application_EndRequest event.

    Because the actual entry for the DbContext has been removed – but the DbContextBuilder entry remains – on next request, it will be invoked and will create a new DbContext for you.

    This should ensure that your DbContext for the current database is created on each request and doesn’t “accumulate” unwanted state tracking entries.

    To further speed things along, you may also want to consider caching the results of intermediate steps in DbContextBuilder.BuildDbContext, such as the compiled model, i.e. this: dbModel.Compile(). (Not sure though if EF5 already does that for you.)

    AR

  7. Sorry, just noticed that the WebDbContextStorage already takes care of context cleanup:

    app.EndRequest += (sender, args) =>
    {
    DbContextManager.CloseAllDbContexts();
    HttpContext.Current.Items.Remove(STORAGE_KEY);
    };

    So, no need to call this yourself in a web scenario.

    AR

  8. Hi Huyrua ,
    How easy it is to use SQL Migration with your framework?

  9. Hello!

    I’m using the 4.0 EF version, and now i’m facing a problem with Many To Many relationships.

    I have like: Article — ArticleTag — Tag

    The problem is when i try to update an Article Entity, changing the Tags.

    It simple doesn’t save my changes, wherever they are.

    What should i do?

    Someone can help?

    Thanks!

  10. Hi Huyrua,

    I have a question that I was hoping to can help. I created the OrderRepository class and CustomerRepository class and both derived from the GenericRepository class but then realized that in order to persist both the Customer and Order entities in the same transaction, I would have to use the UnitOfWork from either CustomerRepository or OrderRepository or an instance of the GenericRepository. Is this how it should work? Thanks.

    • Hi Andy,

      Yes, [Repository].UnitOfWork.SaveChanges() will persist entity.

      • So it sounds like I only need one repository for each of the dbContext that I have? Is there a way to span the transaction across multiple databases? Thanks in advance.

      • So it sounds like I only need one repository for each of the dbContext that I have << Yes, the generic repository is built for it: we only need one to access to db, although you can subclass it to work with specific entity (EmployeeRepository, OrderRepository, etc.)

        Regarding multiple databases, by design, you can create many instances of Repository, each works with a specific database, by passing the connectionString (or an instance of DbContext/ObjectContext which connects to that db) to Repository constructor. Every time you want to persist entity from a repository which works with a specific db, you call [Repository instance].UnitOfWork.SaveChanges();

        If you want to span the transaction across multiple databases, I think you might need to use TransactionScope

    • Thanks for the quick response, huyrua. I understand it better now. BTW, great work!

  11. Hi Huyrua,
    I have a question, how to implement save parent with its child with poco based on the below thread.
    http://stackoverflow.com/questions/7968598/entity-4-1-updating-an-existing-parent-entity-with-new-child-entities/7969372#7969372

    Thanks

    • Assume parent-child is Order-LineItem, try this:

      order.LineItems.Clear();

      order.LineItems.Add(new Order { Price=XX, Quantity=1,… });
      order.LineItems.Add(new Order { Price=XY, Quantity=2,… });

      repository.Update[Order](order);
      repository.UnitOfWork.SaveChanges();

  12. How would you go about adding a generic auditing capabilty to this? The ObjectContext.SavingChanges Event is wrapped up inside the factory class…

  13. Instead of:

    string entitySetName = ((IObjectContextAdapter)DbContext).ObjectContext.MetadataWorkspace.GetEntityContainer(((IObjectContextAdapter)DbContext).ObjectContext.DefaultContainerName, DataSpace.CSpace).BaseEntitySets.Where(bes => bes.ElementType.Name == typeof(TEntity).Name).First().Name;

    Could you do:
    Type entitySetType = typeof(DbSet);
    var entitySetName = DbContext.GetType().GetProperties().First(x => x.PropertyType == entitySetType).Name;

  14. The brackets don’t show => typeof(DbSet[bracket]TEntity[braket])

  15. Hi huyrua,
    I have a dumb question. How would I use the WebDbContextStorage class? My thought is that I would have to add code to the Application_BeginRequest() method as follows:
    DbContextManager.InitStorage(new WebDbContextStorage());
    DbContextManager.Init(“DefaultDb”, new[] { “Infrastructure.Tests” }, true);

    • Hi Andy,

      You can initialize WebDbContextStorage within Global.ascx,cs as below:

      private WebDbContextStorage _storage;
      public override void Init()
      {
      base.Init();
      _storage = new WebDbContextStorage(this);
      }

      protected void Application_BeginRequest(object sender, EventArgs e)
      {
      DbContextInitializer.Instance().InitializeDbContextOnce(() =>
      {
      DbContextManager.InitStorage(_storage);
      DbContextManager.Init(new[] { Server.MapPath(“~/bin/Infrastructure.Tests.dll”) }, false);
      });
      }

      You can replace Infrastructure.Tests.dll with the assembly that contains mapping classes, you can also specify multiple mapping assemblies because the init method accept an array.

      HTH.

  16. Hi huyrua,
    Regarding Transaction, i have this case. I want to add a document then get last document.Id inserted to use it as foreign key in document history.
    as far as i know , i can’t get last inserted id without savechanges().
    savechanges can’t be invoked while i am inside transaction.

    genericRepositroy.UnitOfWork.BeginTransaction();
    genericRepositroy.Add(document);
    // int id = document.Id;
    //documentHistory.Fk_document_id = id;
    genericRepositroy.Add(documentHistory);
    genericRepositroy.UnitOfWork.CommitTransaction();

  17. Is it possible to use SQL Migration feature with your framework?

  18. Hello anh Huy, this is very helpful. I have a question: Is it possible to filter or limits the child items when using Include()? Thank you.

  19. Dear huyrua I am newbie for EF ı need fedback from multiple joins For example ı have user ,
    user has roles roles contains menu menus has forms I want to get forms via multiple joins please help 🙂

  20. Thanks for this great project!
    I implemented Besnik.GenericRepository first, but its to heavy.
    Your project is much more flexable and adds much fewer unneeded abstraction.

  21. Are you by any change planning a implementation of Second Level Caching For Entity Framework?

    For example something like:

    Query Level Caching For Entity Framework And Windows Azure SQL Database Including Transient Fault Handling

  22. Dear A.Huy, Everybody,

    The framework is so cool. But I face a problem with ObjectContext when mapping a entity modified(add or delete property in model). Could you show me how to add more fields(ex. add more field to customer entity to map to database) when developing once there are some data in database(table customer)?

    if (!ctx.DatabaseExists())
    {
    ctx.CreateDatabase();
    }
    else if (_recreateDatabaseIfExists)
    {
    ctx.DeleteDatabase();
    ctx.CreateDatabase();
    }
    }

    Thanks,
    Truong

  23. Hi Guys, What about If I want to select only 2 colums.can you please help me?

  24. Do you have any advice on strategies for multithreading implementations of GenericRepository? It would seem that the static nature of DBContextManager and ObjectContextManager present some challenges if you try to use in multi-threading environments such as building a WCF DAL.

    • Hi Dave
      I am also having the same issue, implementing the solution in WCF environment. Did you manage to solve the issue?

      • I ended up making some small refactorings of and additions to Huy’s code, both to solve this issue and make DALs made from GenericRepository a bit more easily integrated in the Unity IOC. I’ve been meaning to ask Huy if he wanted this as a submission, so maybe this is the impetous for doing something.

        Without going into great detail (or publishing code at this time) the issue resides mostly in the assumption that the DbContext (or ObjectContext in 4.0 and before) should be cached, keyed to the connection string, rather than the DbCompiledModel which is the factory for the DbContext (via DbCompiledModel.CreateObjectContext()). By caching the CompiledModel (which is the real heavyweight startup cost) in an IOC, the DbContext can then be created and destroyed as needed. One can view ObjectContextManager/DbContextManager as a cache that doesn’t use an IOC.

        This really on required making two of the existing classes ‘partial’ so that I could keep my work more easily segregated from Huy’s, specifically GenericRespository and DbContextBuilder. We’ve tested the IOC version extensively and this has resolved the issue of my original post. We have not tested the standalone version which is why I’m hestitant to publish code.

    • Hi Dave,

      Thanks for this, I am more than happy seeing people being interested in the framework and suggest for improvement.

      Is there any chance for you to share your code? The code has moved to github at https://github.com/huyrua/efprs and you can make a pull request yourself.

      Thanks again.

      • Give me a few days (I hope) and I’ll be glad to upload it. I’ll try to assure all of the changes are compatible with the unit tests.

      • I’ve uploaded a net45 version of my code to a github fork (Serenyrddraig/efprs). I got ambitious and updated DbContextManager to use the same technique as I use in the IOC. This was a bit larger change than I previously talked about because some of the previous functionality was no longer needed or could not work as before. For example, GetAllContexts() is irrelevant if the DbContext is manufactured per instance. The existing UnitTests all run cleanly. Changes were made to test startup/shutdown that illustrate the new world order.

        To support unit testing more cleanly, I added a Close() and IDisposable implementation to GenericRepository. This assures that the test cleanup code can release the DbContext cleanly and promptly. The problems this corrects are invisible if the tests are run one at a time. The problems appear when TestExplorer performs a ‘Run All’. Since the existing UnitTests create the database, one cannot leave the DbContext to the GC, else tests may fail for database contention. Also, I changed the Tests app.config so that SqlClient connection pooling is disabled by default. Without this, the tests also fail (at a higher rate) due to contention when trying to create the database.

        I debated adding Close() to IRepository, but I decided to await comment.

      • Exellent! Thank you, Dave.

  25. great post and explanation, just wanted to ask, in the EF5 version of your Repo pattern impl what is the significance of IUnitOfWork ? with the contextmanager class isn’t the need for UOW is removed?
    regards

  26. Hi Huyrua,

    Really liking your framework. I’ve managed to hook it all up and it’s working really well.

    I wonder if you could give me any guidance on using RhinoMock to aid in unit testing. Based on the following test, what would I need to do to get it working:

    [TestClass]
    public class EFTest
    {

    private ISalesRepository salesRepository;
    private IRepository repository;

    [TestInitialize]
    public void SetUp()
    {
    DbContextManager.InitStorage(new SimpleDbContextStorage());
    DbContextManager.Init(“DefaultDb”, new[] { “DataAccess” }, true);

    salesRepository = new SalesRepository();
    repository = new GenericRepository();
    }

    // etc.

    Thanks

    David

  27. Huy, In an idle moment this morning (while sick and the family’s away) I upgraded my branch to 6-RC1. Other than the reference and namespacing issues detailed here http://entityframework.codeplex.com/wikipage?title=Updating%20Applications%20to%20use%20EF6 there were no issues. All tests ran cleanly.

  28. My branch has now been updated to RTM EF6.0.2.

  29. As of EF6, the provider model has become subject to configuration (http://entityframework.codeplex.com/wikipage?title=Rebuilding%20EF%20providers%20for%20EF6) in code or app.config. I have yet to resolve a method that I like so that the former behavior (defaulting to the Sql Server provider) is preserved in GenericRepository. For now, the EntityFramework config section should be used in my branch.

  30. Any plans to update to EF6?

  31. Has anybody a simple MVC application (MVC 5 with membership would be great) using Huyrua’s framework and could share this with us?

  32. David Killian

    Hua, I saw Rowan Miller’s presentation at TechEd2014 (http://channel9.msdn.com/events/TechEd/NorthAmerica/2014/DEV-B417#fbid=) in which he outlines EF7 (https://github.com/aspnet/EntityFramework/wiki). ObjectContext is being completely withdrawn in favor of DbContext so GenericRepository will be affected. I’ve started playing with the pre-alpha code. I’ll post my findings as I discover them.

  33. I believe that returning a IQueryable GetQuery from a repository is one of the best way to throw away one of the key purpose of the Repository pattern itself. Your entire application layers, Business Logic layer or even the Presentation layer, will be closely tied up with Linq-based data access technologies. How can you implement that IRepository interface using Micro-ORM Dapper or the legacy MS Enterprise Library Data Access block ? So what is the point of using the pattern here ?

  34. I don’t know if you’ve discovered https://codefirstfunctions.codeplex.com/, but this is incredibly useful for dealing with TVFs and SPs. I amended my version of GenericRepository (not available publicly yet) as follows

    public DbContextBuilder(string connectionStringName, string[] mappingAssemblies, bool recreateDatabaseIfExists,
    bool lazyLoadingEnabled, params Type[] conventions)

    If the Types specified in the last parameter derive from IStoreModelConvention or IConceptualModelConvention, they will be added to the DbModel.Conventions collection. I may ultimately decide to add Reflective discovery (as in mappingAssemblies) but for my immediate needs, this worked well.

    There are some notes on my usage pattern in the Discussions section on codeplex (my alias is DrDave). For the conventions to be used with GenericRepository, the conventions must be developed in a particular fashion, using the base class, FunctionConvention, not the generic version that is tied to a DbContext specialization.

  35. Hi Huyrua,

    Any plan to support dapper with your existing EF – Repository pattern

Leave a reply to huyrua Cancel reply