mehmetserif
mehmetserif

Reputation: 1227

Is Unit Of Work and Repository Patterns very useful for big projects?

I'm starting a new web project using ASP.NET Webforms + EF4. I'm trying to apply a repository pattern with a unit of work pattern following this tutorial : http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef-code-first-dependeny-injection-in-asp-net-mvc3.html

I think I got the idea but my question is that, when I create a new object in the model, do I also have to define that object in IDALContext of the Unit Of Work? Isn't that a handbreak for rapid development? Also if you work with multiple developers and if you don't want other developers to see your DAL, how can you manage this? Because in this pattern as I understand, when you create a new object in the model you also have to define it in the IDALContext for this tutorial. Sorry I'm so confused by this.

Upvotes: 32

Views: 21872

Answers (4)

Darren
Darren

Reputation: 9479

You should consider "command/query objects" as an alternative, you can find a bunch of interesting articles around this area, but here are some good ones:

https://bigmachine.io/2014/03/04/repositories-and-unitofwork-are-not-a-good-idea/ https://www.dotnetcurry.com/patterns-practices/1461/command-query-separation-cqs

You would stick to a single command object per command to enable simple transactions, avoiding the need for the complexity of the Unit Of Work pattern.

However, if you are thinking a Query object per query is overkill for you, you could well be 100% right. Often you might choose to start with a 'FooQueries' object, which is essentially a Repository but only for Queries. 'Foo' might be your 'domain aggregate' in the DDD sense.

You might then find individual query objects worthwhile later.

As with most things you have to consider on a system by system basis.

Upvotes: 1

Juri
Juri

Reputation: 32890

Now, the first question should be, why do I need a repository or unit of work pattern at all? Couldn't I just use the EF context from the controller, having the full power of directly writing the query I need and returning the data?
Answer: You could, but the real intent behind is testability and thus higher quality, more maintainable code. If you separate your data access and concentrate it on one place, you can mock it out during testing. This allows you to unit test the logic defined within your controller without effectively writing to a data store.

Before starting with the Unit of Work, just use take a look at the Repository pattern. This basically abstracts the data access for a given entity. So you define methods like Filter(), All(), Update(..), Insert(..), Delete(...) and finally, Save(). Actually most of these could be quite easily abstracted to a BaseRepository<TEntity> class such that in the end you'd just have to create a new Repository in rare cases with special behavior. Otherwise it would be something like BaseRepository<Person> personRepo = new BaseRepository<Person>() or BaseRepository<Address> addressRepo = new BaseRepository<Address>() etc.

Why is the Unit of Work needed?
A unit of work represents all operations done during a certain cycle, in a web environment normally per Http request. This means when a new request enters, you instantiate a new Unit of Work, you add new stuff, update or delete it and then you "commit" the changes by invoking the .save()or .commit()..whatever. Actually if you take a closer look at the Entity Framework DbContext (or ObjectContext), they are already representing some kind of Unit of Work.
However if you want to further abstract it, because you'd not necessarily like to have your EF context in your controller classes (remember: testability), then you create a UoW to group your Repositories and also to ensure they all share the same EF context instance. You might achieve the latter also through a DI container (Dependency Injection container).

To your questions: Is it useful in big projects?:
Definitely, especially in big projects. It's all about keeping responsibilities separated (data access, business logic, domain logic) and thus making things testable.

Upvotes: 112

Mosh
Mosh

Reputation: 6044

Software design patterns are designed to solve specific problems with the right context, and if used inappropriately, they'll lead to extra unnecessary complexity without providing any values.

So, what are the problems that the repository pattern aims to solve?

1- Minimizing duplicate query logic: in large applications, you may find many complex LINQ queries duplicated in a few places. If that's the case, you can use the repository pattern to encapsulate these queries and minimise duplication.

2- Better separation of concerns: Imagine a complex query to get the top selling courses in a given category that involves eager loading, joining, grouping, filtering, etc.

When you implement such large complex queries in your services/controllers, you'll end up with fat services/controllers. These classes become hard to unit test as they'll require a lot of noisy stubbing. Your unit tests become long, fat, and unmaintainable.

If you're facing this problem, perhaps you might consider using the repository pattern. In this example, we can encapsulate the complex query to get top selling courses in a repository:

courseRepository.GetTopSellingCourses(int categoryId, int count);

This way, your services/controller will no longer deal with eager loading, joining, grouping, etc. Instead, they'll delegate to the repository. Remember, eager loading, joining and grouping, etc are querying logic and belongs to your data access layer, not your services or presentation layer.

3- Decoupling your application architecture from persistence frameworks: when you use Entity Framework classes (e.g. DbContext, DbSet, etc) directly in your application, your application is tightly coupled to Entity Framework. If you plan to switch to a different O/RM sometime in the future, or even a newer version of Entity Framework with a different model, you may have to modify many parts of your application and this can lead to new bugs in your application. You can use the repository pattern to decouple your application architecture from persistence frameworks such as Entity Framework. This way, you'll have the freedom to change to a different O/RM with minimal impact on your application.

Check out this video for more details:

https://youtu.be/rtXpYpZdOzM

Upvotes: 13

saintedlama
saintedlama

Reputation: 6898

Martin Fowler describes the repository's role as: "A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection". What Entity Framework 4.1 exposes is a repository in that sense. Also EF has a unity of work built in. So my advice is to ignore the blog article you mentioned in your question.

Code like this is not just only useless or worthless but dangerous because there is no benefit added to your code but a dependency!

public interface IUnitOfWork:IDisposable
{
    int SaveChanges();
}

public interface IDALContext : IUnitOfWork
{
    ICategoryRepository Categories { get; }
    IProductRepository Products { get; }
}

To answer your question having some abstraction that mediates between the domain and data mapping layers, acting like an in-memory domain object collection is a must for "big" projects. And having a UnitOfWork mechanism under the hood can help decouple your business logic from access to a some data access abstraction.

TL;TR; Repository and UnitOfWork can help you but don't apply it like in the given blog post.

Upvotes: 22

Related Questions