4

I am re-examining my implementation of the generic unit of work and repository framework.

I am using EF6, and VS2013. As such, VS contains WebAPI controller templates that auto-generate WebAPI 2 OData Controller with Actions, using Entity Framework code like this:

// GET odata/UserProjects(5)/WebsiteRequiredKeywords
        [Queryable]
        public IQueryable<WebsiteRequiredKeyword> GetWebsiteRequiredKeywords([FromODataUri] int key)
        {
            return _db.Websites.Where(m => m.WebsiteId == key).SelectMany(m => m.WebsiteRequiredKeywords);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _db.Dispose();
            }
            base.Dispose(disposing);
        }

        private bool WebsiteExists(int key)
        { . . .

In looking at the CustomerController class in the sample code - it all looks very familiar to the auto-generated code in the VS2013 template. If I was using the generic framework, I would have to refactor the auto-generated code to make use of the generic repository syntax, modify the constructor, etc. While I'm sure there is a way to modify the template generation process to conform to this generic repository (or add our own template to the VS template) - this amount of work seems to be unnecessary.

The generic scaffolding template uses the same database context. As I understand it, this is synonymous with a unit of work pattern.

I am trying to now find the value in having to perform any of this additional work. While I have successfully used the generic repository and unit of work patterns in previous projects, for new ones, is it just more work than it's worth (as there is some concept duplication b/t EF and this pattern as well)?

-- UPDATE --

With some minor modifications to the auto-generated code, what would I need to do after implementing something like this:

public class ProjectEditorController : ODataController
{
    //private MyDatabaseNameContext db = new MyDatabaseNameContext();  // auto-generated code

    private DbContext _db;

    public ProjectEditorController(DbContext dbContext)
    {
        _db = dbContext;
    }
    . . .

The problem with this code is that now there is no concrete context, and doing things like:

return SingleResult.Create(_db.Websites.Where(website => website.WebsiteId == key));

...will not work, as there is no concrete link between db and the entities, ie. Websites.

In using DI for WebAPI Controllers, you still have to define a repository. Is this a case where if I wanted to inject the dbContext I need to use the generic repo?

In short, is this accurate: If you want to efficiently use dependency injection, then you need a generic repository. Otherwise, you need to define a repository interface for all your EF entities, unless you use the IDependency resolver, as suggested at the end of this article.

ElHaix
  • 12,846
  • 27
  • 115
  • 203
  • Do these new templates share the same data-context? Since, sharing the data-context is the key part of the UOW pattern if they don't then it's not an equivalent comparison. Or is it? – Big Daddy Mar 25 '14 at 18:06
  • Is there a worthwhile reason to do all that refactoring? If there is not then relax. It's easy to over engineer, and you can always refactor later when there is a case for doing so. If it is worthwhile then install the [MVC 5 Code Templates](https://www.nuget.org/packages/Mvc5CodeTemplatesCSharp/) and save yourself some time if you're going to keep doing it. – Jeremy Cook Mar 25 '14 at 18:14
  • @BigDaddy - I updated the default code with a new constructor, where you can define the context. See the updated question. – ElHaix Mar 25 '14 at 18:16
  • 3
    In years past when we didn't have abstractions like EF a repository made a lot of sense. With EF in the picture, I've found that implementing a repository can be a lot of extra work with very little gain (or none). So what I tend to do (unless there's a good reason to do otherwise) is create extension methods of IQuerable and organize my code that way. 2p – Jeremy Cook Mar 25 '14 at 18:18
  • @ElHaix...It looks like you could use a DI container to inject your context. – Big Daddy Mar 25 '14 at 18:19
  • @BigDaddy - Right - and the reason for the additional constructor code. – ElHaix Mar 25 '14 at 18:20
  • @ElHaix...Where's the data-context initialized? In a generic-rep pattern, we'd do it in the GenericRepository class. – Big Daddy Mar 25 '14 at 18:29
  • @BigDaddy - I made a further update in realizing there is would be an issue. I am using Autofac to inject the context into the controller. While that was working with the generic repo, I'm not sure on what now needs to be done without this generic repo. Is there were the need for a generic repo is, if you want DI? – ElHaix Mar 25 '14 at 18:42
  • @JeremyCook - In your case were you using dependency injection, and if so, how did you efficiently accomplish it without using a generic repository? – ElHaix Mar 25 '14 at 19:29
  • @ElHaix you can inject a DbContext if you want, in fact if you are using DI with a repository you are probably already injecting the DbContext into the repository. Same deal here. As for me, I've hopped off the IoC/DI bandwagon and only use one when there is truly good cause. If your DbContext only needs to be generated once during a page request then it is not inefficient to create it in the constructor of your Web API controller via `this(new MyDbContext())`. I usually have two constructors: the one that takes parameters enables unit testing, and the parameterless one let's me avoid IoC. – Jeremy Cook Mar 25 '14 at 19:37

1 Answers1

3

Ayende sums it up pretty well here. Don't add abstraction you don't need.

Jeremy Danyow
  • 26,470
  • 12
  • 87
  • 133
  • 2
    There's much difference of opinion on the subject. Many people disagree as well. Unfortunately, Ayende's response is to just use the context directly in your controllers, which has its own set of problems. If you question him on it, he insists that's not what he meant, but he refuses to supply a decent example of what he did mean. Hell, one example of his uses a actual singletons to store the data context. – Erik Funkenbusch Mar 25 '14 at 19:48
  • 1
    @ErikFunkenbusch- _There's much difference of opinion on the subject_. That's for sure! – Jeremy Danyow Mar 25 '14 at 20:21