NOT using repository pattern, use the ORM as is (EF)
Solution 1:
I've gone down many paths and created many implementations of repositories on different projects and... I've thrown the towel in and given up on it, here's why.
Coding for the exception
Do you code for the 1% chance your database is going to change from one technology to another? If you're thinking about your business's future state and say yes that's a possibility then a) they must have a lot of money to afford to do a migration to another DB technology or b) you're choosing a DB technology for fun or c) something has gone horribly wrong with the first technology you decided to use.
Why throw away the rich LINQ syntax?
LINQ and EF were developed so you could do neat stuff with it to read and traverse object graphs. Creating and maintain a repository that can give you the same flexibility to do that is a monstrous task. In my experience any time I've created a repository I've ALWAYS had business logic leak into the repository layer to either make queries more performant and/or reduce the number of hits to the database.
I don't want to create a method for every single permutation of a query that I have to write. I might as well write stored procedures. I don't want GetOrder
, GetOrderWithOrderItem
, GetOrderWithOrderItemWithOrderActivity
, GetOrderByUserId
, and so on... I just want to get the main entity and traverse and include the object graph as I so please.
Most examples of repositories are bullshit
Unless you are developing something REALLY bare-bones like a blog or something your queries are never going to be as simple as 90% of the examples you find on the internet surrounding the repository pattern. I cannot stress this enough! This is something that one has to crawl through the mud to figure out. There will always be that one query that breaks your perfectly thought out repository/solution that you've created, and it's not until that point where you second guess yourself and the technical debt/erosion begins.
Don't unit test me bro
But what about unit testing if I don't have a repository? How will I mock? Simple, you don't. Lets look at it from both angles:
No repository - You can mock the DbContext
using an IDbContext
or some other tricks but then you're really unit testing LINQ to Objects and not LINQ to Entities because the query is determined at runtime... OK so that's not good! So now it's up to the integration test to cover this.
With repository - You can now mock your repositories and unit test the layer(s) in between. Great right? Well not really... In the cases above where you have to leak logic into the repository layer to make queries more performant and/or less hits to the database, how can your unit tests cover that? It's now in the repo layer and you don't want to test IQueryable<T>
right? Also let's be honest, your unit tests aren't going to cover the queries that have a 20 line .Where()
clause and .Include()
's a bunch of relationships and hits the database again to do all this other stuff, blah, blah, blah anyways because the query is generated at runtime. Also since you created a repository to keep the upper layers persistence ignorant, if you now you want to change your database technology, sorry your unit tests are definitely not going to guarantee the same results at runtime, back to integration tests. So the whole point of the repository seems weird..
2 cents
We already lose a lot of functionality and syntax when using EF over plain stored procedures (bulk inserts, bulk deletes, CTEs, etc.) but I also code in C# so I don't have to type binary. We use EF so we can have the possibility of using different providers and to work with object graphs in a nice related way amongst many things. Certain abstractions are useful and some are not.
Solution 2:
The repository pattern is an abstraction. It's purpose is to reduce complexity and make the rest of the code persistant ignorant. As a bonus it allows you to write unit tests instead of integration tests.
The problem is that many developers fail to understand the patterns purpose and create repositories which leak persistance specific information up to the caller (typically by exposing IQueryable<T>
). By doing so they get no benefit over using the OR/M directly.
Update to address another answer
Coding for the exception
Using repositories is not about being able to switch persistence technology (i.e. changing database or using a webservice etc instead). It's about separating business logic from persistence to reduce complexity and coupling.
Unit tests vs integration tests
You do not write unit tests for repositories. period.
But by introducing repositories (or any other abstraction layer between persistance and business) you are able to write unit tests for the business logic. i.e. you do not have to worry about your tests failing due to an incorrectly configured database.
As for the queries. If you use LINQ you also have to make sure that your queries work, just as you have to do with repositories. and that is done using integration tests.
The difference is that if you have not mixed your business with LINQ statements you can be 100% sure that it's your persistence code that are failing and not something else.
If you analyze your tests you will also see that they are much cleaner if you have not mixed concerns (i.e. LINQ + Business logic)
Repository examples
Most examples are bullshit. that is very true. However, if you google any design pattern you will find a lot of crappy examples. That is no reason to avoid using a pattern.
Building a correct repository implementation is very easy. In fact, you only have to follow a single rule:
Do not add anything into the repository class until the very moment that you need it
A lot of coders are lazy and tries to make a generic repository and use a base class with a lot of methods that they might need. YAGNI. You write the repository class once and keep it as long as the application lives (can be years). Why fuck it up by being lazy. Keep it clean without any base class inheritance. It will make it much easier to read and maintain.
(The above statement is a guideline and not a law. A base class can very well be motivated. Just think before you add it, so that you add it for the right reasons)
Old stuff
Conclusion:
If you don't mind having LINQ statements in your business code nor care about unit tests I see no reason to not use Entity Framework directly.
Update
I've blogged both about the repository pattern and what "abstraction" really means: http://blog.gauffin.org/2013/01/repository-pattern-done-right/
Update 2
For single entity type with 20+ fields, how will you design query method to support any permutation combination? You dont want to limit search only by name, what about searching with navigation properties, list all orders with item with specific price code, 3 level of navigation property search. The whole reason
IQueryable
was invented was to be able to compose any combination of search against database. Everything looks great in theory, but user's need wins above theory.
Again: An entity with 20+ fields is incorrectly modeled. It's a GOD entity. Break it down.
I'm not arguing that IQueryable
wasn't made for quering. I'm saying that it's not right for an abstraction layer like Repository pattern since it's leaky. There is no 100% complete LINQ To Sql provider (like EF).
They all have implementation specific things like how to use eager/lazy loading or how to do SQL "IN" statements. Exposing IQueryable
in the repository forces the user to know all those things. Thus the whole attempt to abstract away the data source is a complete failure. You just add complexity without getting any benefit over using the OR/M directly.
Either implement Repository pattern correctly or just don't use it at all.
(If you really want to handle big entities you can combine the Repository pattern with the Specification pattern. That gives you a complete abstraction which also is testable.)
Solution 3:
IMO both the Repository
abstraction and the UnitOfWork
abstraction have a very valuable place in any meaningful development. People will argue about implementation details, but just as there are many ways to skin a cat, there are many ways to implement an abstraction.
Your question is specifically to use or not to use and why.
As you have no doubt realised you already have both these patterns built into Entity Framework, DbContext
is the UnitOfWork
and DbSet
is the Repository
. You don’t generally need to unit test the UnitOfWork
or Repository
themselves as they are simply facilitating between your classes and the underlying data access implementations. What you will find yourself needing to do, again and again, is mock these two abstractions when unit testing the logic of your services.
You can mock, fake or whatever with external libraries adding layers of code dependencies (that you don’t control) between the logic doing the testing and the logic being tested.
So a minor point is that having your own abstraction for UnitOfWork
and Repository
gives you maximum control and flexibility when mocking your unit tests.
All very well, but for me, the real power of these abstractions is they provide a simple way to apply Aspect Oriented Programming techniques and adhere to the SOLID principles.
So you have your IRepository
:
public interface IRepository<T>
where T : class
{
T Add(T entity);
void Delete(T entity);
IQueryable<T> AsQueryable();
}
And its implementation:
public class Repository<T> : IRepository<T>
where T : class
{
private readonly IDbSet<T> _dbSet;
public Repository(PPContext context)
{
_dbSet = context.Set<T>();
}
public T Add(T entity)
{
return _dbSet.Add(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
public IQueryable<T> AsQueryable()
{
return _dbSet.AsQueryable();
}
}
Nothing out of the ordinary so far but now we want to add some logging - easy with a logging Decorator.
public class RepositoryLoggerDecorator<T> : IRepository<T>
where T : class
{
Logger logger = LogManager.GetCurrentClassLogger();
private readonly IRepository<T> _decorated;
public RepositoryLoggerDecorator(IRepository<T> decorated)
{
_decorated = decorated;
}
public T Add(T entity)
{
logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString() );
T added = _decorated.Add(entity);
logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
return added;
}
public void Delete(T entity)
{
logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
_decorated.Delete(entity);
logger.Log(LogLevel.Debug, () => DateTime.Now.ToLongTimeString());
}
public IQueryable<T> AsQueryable()
{
return _decorated.AsQueryable();
}
}
All done and with no change to our existing code. There are numerous other cross cutting concerns we can add, such as exception handling, data caching, data validation or whatever and throughout our design and build process the most valuable thing we have that enables us to add simple features without changing any of our existing code is our IRepository
abstraction.
Now, many times I have seen this question on StackOverflow – “how do you make Entity Framework work in a multi tenant environment?”.
https://stackoverflow.com/search?q=%5Bentity-framework%5D+multi+tenant
If you have a Repository
abstraction then the answer is “it’s easy add a decorator”
public class RepositoryTennantFilterDecorator<T> : IRepository<T>
where T : class
{
//public for Unit Test example
public readonly IRepository<T> _decorated;
public RepositoryTennantFilterDecorator(IRepository<T> decorated)
{
_decorated = decorated;
}
public T Add(T entity)
{
return _decorated.Add(entity);
}
public void Delete(T entity)
{
_decorated.Delete(entity);
}
public IQueryable<T> AsQueryable()
{
return _decorated.AsQueryable().Where(o => true);
}
}
IMO you should always place a simple abstraction over any 3rd party component that will be referenced in more than a handful of places. From this perspective an ORM is the perfect candidate as it is referenced in so much of our code.
The answer that normally comes to mind when someone says “why should I have an abstraction (e.g. Repository
) over this or that 3rd party library” is “why wouldn’t you?”
P.S. Decorators are extremely simple to apply using an IoC Container, such as SimpleInjector.
[TestFixture]
public class IRepositoryTesting
{
[Test]
public void IRepository_ContainerRegisteredWithTwoDecorators_ReturnsDecoratedRepository()
{
Container container = new Container();
container.RegisterLifetimeScope<PPContext>();
container.RegisterOpenGeneric(
typeof(IRepository<>),
typeof(Repository<>));
container.RegisterDecorator(
typeof(IRepository<>),
typeof(RepositoryLoggerDecorator<>));
container.RegisterDecorator(
typeof(IRepository<>),
typeof(RepositoryTennantFilterDecorator<>));
container.Verify();
using (container.BeginLifetimeScope())
{
var result = container.GetInstance<IRepository<Image>>();
Assert.That(
result,
Is.InstanceOf(typeof(RepositoryTennantFilterDecorator<Image>)));
Assert.That(
(result as RepositoryTennantFilterDecorator<Image>)._decorated,
Is.InstanceOf(typeof(RepositoryLoggerDecorator<Image>)));
}
}
}
Solution 4:
First of all, as suggested by some answer, EF itself is a repository pattern, there is no need to create further abstraction just to name it as repository.
Mockable Repository for Unit Tests, do we really need it?
We let EF communicate to test DB in unit tests to test our business logic straight against SQL test DB. I don't see any benefit of having mock of any repository pattern at all. What is really wrong doing unit tests against test database? As it is bulk operations are not possible and we end up writing raw SQL. SQLite in memory is perfect candidate for doing unit tests against real database.
Unnecessary Abstraction
Do you want to create repository just so that in future you can easily replace EF with NHbibernate etc or anything else? Sounds great plan, but is it really cost effective?
Linq kills unit tests?
I will like to see any examples on how it can kill.
Dependency Injection, IoC
Wow these are great words, sure they look great in theory, but sometimes you have to choose trade off between great design and great solution. We did use all of that, and we ended up throwing all at trash and choosing different approach. Size vs Speed (Size of code and Speed of development) matters huge in real life. Users need flexibility, they don't care if your code is great in design in terms of DI or IoC.
Unless you are building Visual Studio
All these great design are needed if you are building a complex program like Visual Studio or Eclipse which will be developed by many people and it needs to be highly customizable. All great development pattern came into picture after years of development these IDEs has gone through, and they have evolved at place where all these great design patterns matter so much. But if you are doing simple web based payroll, or simple business app, it is better that you evolve in your development with time, instead of spending time to build it for million users where it will be only deployed for 100s of users.
Repository as Filtered View - ISecureRepository
On other side, repository should be a filtered view of EF which guards access to data by applying necessary filler based on current user/role.
But doing so complicates repository even more as it ends up in huge code base to maintain. People end up creating different repositories for different user types or combination of entity types. Not only this, we also end up with lots of DTOs.
Following answer is an example implementation of Filtered Repository without creating whole set of classes and methods. It may not answer question directly but it can be useful in deriving one.
Disclaimer: I am author of Entity REST SDK.
http://entityrestsdk.codeplex.com
Keeping above in mind, we developed a SDK which creates repository of filtered view based on SecurityContext which holds filters for CRUD operations. And only two kinds of rules simplify any complex operations. First is access to entity, and other is Read/Write rule for property.
The advantage is, that you do not rewrite business logic or repositories for different user types, you just simply block or grant them the access.
public class DefaultSecurityContext : BaseSecurityContext {
public static DefaultSecurityContext Instance = new DefaultSecurityContext();
// UserID for currently logged in User
public static long UserID{
get{
return long.Parse( HttpContext.Current.User.Identity.Name );
}
}
public DefaultSecurityContext(){
}
protected override void OnCreate(){
// User can access his own Account only
var acc = CreateRules<Account>();
acc.SetRead( y => x=> x.AccountID == UserID ) ;
acc.SetWrite( y => x=> x.AccountID == UserID );
// User can only modify AccountName and EmailAddress fields
acc.SetProperties( SecurityRules.ReadWrite,
x => x.AccountName,
x => x.EmailAddress);
// User can read AccountType field
acc.SetProperties<Account>( SecurityRules.Read,
x => x.AccountType);
// User can access his own Orders only
var order = CreateRules<Order>();
order.SetRead( y => x => x.CustomerID == UserID );
// User can modify Order only if OrderStatus is not complete
order.SetWrite( y => x => x.CustomerID == UserID
&& x.OrderStatus != "Complete" );
// User can only modify OrderNotes and OrderStatus
order.SetProperties( SecurityRules.ReadWrite,
x => x.OrderNotes,
x => x.OrderStatus );
// User can not delete orders
order.SetDelete(order.NotSupportedRule);
}
}
These LINQ Rules are evaluated against Database in SaveChanges method for every operation, and these Rules act as Firewall in front of Database.
Solution 5:
There is a lot of debate over which method is correct, so I look at it as both are acceptable so I use ever which one I like the most (Which is no repository, UoW).
In EF UoW is implemented via DbContext and the DbSets are repositories.
As for how to work with the data layer I just directly work on the DbContext object, for complex queries I will make extension methods for the query that can be reused.
I believe Ayende also has some posts about how abstracting out CUD operations is bad.
I always make an interface and have my context inherit from it so I can use an IoC container for DI.