Ok, this is my favorite lecture in this
course, because there are so many blog posts and videos about repositories and many of them conflict with each other which made me confused about the
repository pattern for a long time. So in this lecture, I'm gonna explain clearly
what repository is and what is not why and if we need it and address some
of the misconceptions about repositories. So, what is the repository pattern? I'm
gonna start with a definition from Martin Fowler's book: Patterns of Enterprise
Application Architecture. Repository mediates between the domain and data
mapping layers acting like an in-memory collection of domain objects. I've
highlighted in memory collection in this phrase because that's the key here. So what
are the benefits of the repository pattern? The first one, again, based on
Martin Fowler's book is that it minimizes duplicate query logic. So, imagine
in a few different places in our application we need to get the first
five top-selling courses in a given category. Without the repository pattern,
we'll end up duplicating this query logic over and over in different places. In situations
like this, we can encapsulate this logic in a repository and simply call a
method like get top-selling courses which takes two parameters: the category
and the number of courses to return. So this is one benefit of the pattern.
Another benefit of the repository pattern is that it decouples your
application from persistence frameworks in this case Entity Framework. So, in the
future if you decide to switch to a different persistence framework you can
do so with minimal impact on the rest of your application. Now the first argument
that comes here is that some developers say: "But who would change the persistence
framework of an application?" Well, let me tell you something. The fact
that this does not happen very often is not because it's not desirable. It's
because most of the time application architectures are so tangled
and tightly coupled to Entity Framework that it doesn't give us the freedom to change
it. A while ago I read somewhere on a blog that on average every two years we
get a new persistence framework and I think that's very true. First we
had ADO.NET so we used SqlConnection and SqlCommand to access
the database. Then, LinqToSql came along but it didn't prove to be
successful. Next, Entity Framework version 1 arrived
which had so many issues. Nearly at the same time NHibernate got popular. Then, after four
versions Entity Framework reached a stage that it was reasonable to be used in
production; but still at this point it had a heavy object model that was not
testable. Then, they introduced a new model DbContext. Now, they're working
on version 7 which is a complete rewrite and there are some breaking changes. Not to
mention that along these lines we have had other persistence frameworks like
Dapper, ORMLite, PetaPocos and so on. So, our persistence frameworks are
constantly changing and evolving and if you want to have the freedom to explore
a different persistence framework with minimal impact on your application
that's when you should use the repository pattern. Now, there is also
another benefit with the repository pattern that some claim: that it makes it
easier to unit test your application but that's partially true and that's if you're
using an older version of Entity Framework with ObjectContext and ObjectSet. The new DbContext and DbSet objects have interfaces that you can mock to
unit test your applications so you don't necessarily need the repository pattern
to unit test your application. Now, the theory behind, what is the repository
in practice? In a nutshell, this is what your repositories should look like. They
should act like a collection of objects in memory. So we have methods to add or
remove an object, get an object by ID, get all objects or find them using a predicate.
Note that here we do not have a method called update because with collections
in memory if we want to update an object, we simply get it from the
collection and change it. We don't tell the collection to update an object and
that's one of the areas that a lot of developers get wrong. A repository should
not have the semantics of your database. It should be like a collection of
objects in memory and shouldn't have methods like Update and Save. Now, with this, the first
question that pops into a lot of people's head, including myself along time
ago, is: "if the repository acts as a collection of objects in memory, how are
we going to save these objects and changes to them to the database?" That's
when the unit of work pattern comes into the picture. A unit of work maintains a list of objects affected by
a business transaction and coordinates the writing out of changes. And this is where things get interesting.
Some developers argue that both the repository and unit of work patterns are
already implemented in entity framework and there's no need to recreate them as
this would lead to unnecessary complexity. Let's see if this argument is
valid. So the argument says that DbSet has a
collection like interface so it has methods like add, remove, find, where and
as you see it doesn't have methods like update and save. So perfect! Also the argument claims that the DbContext
acts as the unit of work. It keeps track of changes in the objects
and coordinates the writing out of changes. As you see here DbContext has references to one or
more DbSets and a save methods actually implemented here, so again it makes sense
because as I explained, the Save method should not be in the repository. Plus,
chances are in a business transaction we may work with more than one repository.
So that's the reason the Save method should be in the unit of work. So it'll
coordinate persisting changes across multiple repositories in one transaction. So, on the surface, yes Entity Framework
DbSets and DbContext indeed look like repositories and unit of work.
But there's a hidden problem here with the implementation of these patterns in
entity framework. Let's review the benefits of the repository pattern again
and see if our DbSets satisfy the definition of repositories. So, a
repository minimizes duplicate query logic and I showed you an example of this before.
Now, the problem with DbSets and LINQ extension methods implemented on them is
that they return IQueryable and this means if you want to get top-selling
courses you will end up repeating this few lines in a few different
places in your application. In fact, in one of the projects I worked on recently,
this was exactly the case. DbContext was everywhere and we had long fat
queries repeated over and over. What you see here is actually a very simple
example. I've seen worse! So, the implementation of DbSet does
not really help with minimizing duplicate query logic. Yes you can argue that we can
use extension methods to encapsulate these logics into a method on a DbSet and
believe me, we had exactly the scenario in that project. In my opinion, this
solution treats the symptoms, not the actual problem. Because even if you use
extension methods, all the existing LINQ extension methods still return
IQueryable, and next time a developer joining your team is going to use them to write
new queries. So in this case ideally we want a repository that has a
method like get top selling courses and all the querying logic is encapsulated their there. DbContext should be a private field in the repository and not exposed to the
outside. It's the implementation detail. Now, the second benefit of repository pattern is
that it decouples your application from persistence frameworks. When you're using DbContext and DbSets directly in your application, your application is tightly
coupled to Entity Framework if you want to upgrade to a newer version of Entity
Framework with a different model or switch to a different ORM you need to
modify your application code directly. However, if all this is behind a
repository and your application code relies on the repository to return the
right data, it doesn't matter what is inside the repository. Today, you can use
entity framework in a repository, tomorrow you may decide for optimization reasons
to replace it with stored procedures. Your application code will not be
affected in any way. It simply asked the repository to get the data. Repository
does its job. It doesn't matter what is inside a repository, how it's done. Are we using stored procedures, are we using
entity framework, are we using ObjectContext or DbContext or a different ORM, it doesn't
matter. So with all these, in my opinion while DbSet and DbContext in entity
framework, do look like the implementation of the repository and unit of work,
they don't really bring the architectural benefit that we can get from these
patterns. If you have not read about clean architecture, I highly recommend
you to look it up. Uncle Bob or Robert C Martin has a
beautiful post on the topic, and my favorite line in that post is:
architecture should be independent of frameworks. This allows you to use such
frameworks as tools rather than having to cram your system into their limited
constraints. So that's why using patterns like the repository pattern help you
decouple from frameworks such as entity framework. Now that theory aside, I want you to
think like an engineer. Be pragmatic. Keep it simple. My favorite quote is that
simplicity is the ultimate sophistication. Just adhearing to clean
architecture principles and using all sorts of patterns doesn't necessarily
make you a better coder, neither does it improve the quality of your software. Not
every application needs sophisticated architecture like this! A lot of times
you might be building simple or proof of concept applications for a limited audience.
Please don't do over engineering! A while ago, I worked for five months on an
application where its requirements were rapidly changing and there I didn't use
any of the stuff I talked about in this lecture. I had no repositories, no clean
architecture, no unit testing, not even dependency injection! Because we were not
sure if the application would even make it to the production for financial and
political reasons! And guess what? The application never made it to the
production! So if I spent a lot of time adhering to all these architectural best
practices, I had just wasted my time! It wouldn't bring any values. some developers
simply use patterns without really understanding the problem and this way
they feel good about themselves. My pragmatic suggestion to you is:
use patterns only when you need to. Don't use them as deodorants to
make smelly code smell good. In the next lecture, I'll show you how to implement the
repository and unit of work patterns. I hope you enjoyed this lecture and thank
you for watching. Ok, now let's see how we can implement the repository pattern
with any family Chris I'm going to show you a diagram of the interfaces and
classes and then we'll explore Ducote so to start with we need a repository and
face this interface is like the interface for a collection of objects in
memory so it has methods link had removed get and fined again here we're
not going to have a date or safe mixed going to implement this interface in
class called repository and say this repository gonna have ADB context a
generic Teva context so what you see here is completely
generic it's got nothing to do with our application you can reuse this interface
and a concrete implementation of it in any applications in context of our
application pluto for each kennedy we're gonna have a repository of course any
gonna have an interface called I chorus repository in this interface for going
to define any operations specific courses that are not in our generic
repository for example we can have a method like get top-selling courses or
another method get courses with authors which uses eager loading to load the
courses and their authors so this is one of the key things here anything to do with eager loading or
explicit learning is data access concern you application code your business logic
should not care how this is done this is the implementation dito that's what
happened inside a repository your business logic layer or syria says
simply tell the repository give me courses and their officers and the
repository works out how it should be done now here I cross repository just
declares the contract so we need to implemented in a class like course
repository in this diagram course repository derives from our generic
repository because a lot of our data access Cook is similar but it also
additionally implements I chorus repository interface is going to have
implementations for these two methods you see on the right time next unit so we need an interface like I
unit of work this interface is specific to our application so it's going to
expose various repositories based on the entities we have in our application for
example here we have two properties courses and hospice and two types are I
cross repository and I author repository respectively and know that here we have
a method called complete which indicate the end of a unit of work we could cause
this safe but I personally prefer to call it complete because this is
completion of a unit of work next when it a class to implement that so we're
going to call this unit aware now the sleepover to Visual Studio and
see on these interfaces and implementations in action I'm gonna take
you through every interface and implementation but you can also download
all the source code and the supplementary materials obvious lecter
let's start with I repository ok here's my I repository anaphase know
that this is a generic interface where a TNT is a class some developers like to
have a market in a face like i entity and decorate their domain classes like
course author tank cover and so on that interface and here you could say we're a
TNT is I entity I personally don't quite like market interfaces because it's like
pulling herself it doesn't bring any value anyway here we have three groups
of methods the first group is for finding objects the second group is for
hanging objects and a third group is for removing objects to the first method get
receives and I D and returns on anybody but then I D yes I have get all which
returns on objects and find which takes a pretty kate is predicated is an
expression expression a funk so this means we can use a lambda expression to
filter objects exactly the same way we use that we're method with link next we have which adds one object to
the repository and a drained which adds a list of objects and similarly we have
been removed and remove range so as you see this repository in the face is like
a collection it doesn't have metals like update are safe now let's look at its
implementation here is made of the repository know that it takes a
diva context it is constructor and this is generic it's got nothing to do with
our application so it's not pluto context I have declared this as
protected because indirect classes like course repository or author repository
I'm going to use it now look at get all this method returns
I innumerable it doesn't return IQueryable and that's the key thing here
the repositories should not return IQueryable because this can give the
wrong impression to the upper layers like services or controllers that they
can use desire to build grace which is completely against the idea of using a
repository in the first place the repositories should encapsulate your
queries so you do not repeat them so here in get all I seem to call you
names to return an IEnumerable the implementation of other metals like find
out of range is pretty similar to normandy be context to adding objects or
removing them so nothing special here again you can
download the source code study on your own so I know that this I repository and
its implementation are completely generic they got nothing to do with our
application now let's take a look at the custom repository I'm gonna show you I
course repository so this interface to rise from our
generic repository interface so it's going to inherit all those generic
operations like add range remove get and so on but it also declares two
additional operations get top-selling courses and get courses with authors
again know that both these methods returned IEnumerable to be going to a
second-degree inside the repository and return a list of objects to declined now let's take a look at the
implementation of this interface so this class course repository derives from our
generic repository because we don't want a repeat of that code for adding
removing and getting objects from the repository from repository of course and also
implement high course repository so here's the implementation of the method
in interface now get top-selling courses does not really have the actual
implementation of getting top-selling courses I am doing here for simplicity
is ordering courses by their full price and getting the first few most expensive
courses so this is not really top-selling I did good idea to look at
this method of courses with authors this
method uses eager loading to load courses and their officers so we started
with courses that include also earns an order by skip and take this is for
paging because we have supplied a paging they underpaid size so this is another
technique that you can use these repositories something about a person
they have to use IQueryable so that they can apply filtering in the upper layers
like services of controllers at your filtering four pages shouldn't happen in
those layers its data access code that should happen inside your repositories
so that way to do that is by passing two parameters here page index and paid size
could optionally give this a default value to make calling this method easier
but paid sizes 10 lady 50 here I have declared a property for simplicity this
property is of type lose a context so I am doing he's casting the context that
you're inheriting from the generic repository the base of this class
requesting that too few to context otherwise in every method here I had to
repeat this good chance to context first and then get access to the course is d
be set now at the unit of work so here's my I used
to work in a face note that it hurts from my disposable and exposes two
repositories course repository and author repository a note that both these
are interfaces this is for testability so we can look this interface and its
properties in our unit tests and here's my complete method let's take a look at
the implementation so this unit to work as I said is specific to our application
so it receives Pluta context in the constructor and story in a private field
here and this is the interesting part it uses the same context to initialize both
repositories so the client of unit of work will instantiate a polluter context
and then we'll use this context across all repositories next year is the
implementation of the properties courses and authors we spread declared in our
inner fence incomplete method simply cause the safe changes on the context
and here is the implementation of the disposed method so he simply dispose the
context now can we use all these interfaces and
classes altogether application let me show you an example
so any console with simply have this using block and
inside this block we initialize a journey to work with a new political
context that this is not how you do it in a spin on the name BC or WPF
applications there we don't really use the using block this is just for console
applications will show you how to use this later in asp.net MVC and WPF oK now
let's go through three examples I'm gonna get a course with I D one so I
start with you need to work exactly like how we start with TV context here we
have authors and courses again similar to Dima context the differences is that
of deeply said these properties are repositories and these repositories as I
explained itinerary unelected TV said they know nothing about any framework so
this may be decoupled our application from any family so you directed courses
. get theirs I D that's it another example I wanna get all courses
with their authors so you know that courses and because this is I cross
repository here we have those additional methods that were declared in I cross
repository so get course as with authors first page and debate size is let's say
four so everything you learned in this course
about TV context and dv7 scoring a place here the only difference he's working
with different interfaces that are not part of any family let's go through one
more example hurting the last talked about removing objects you saw
that in order to remove an author and his courses because we didn't have
cascade delete we had to remove the courses first in order to remove the
author someone to remove an author first I need to get it unit of work done on Thurs don't get
author we'd courses so this method was declared in Ohio author repository specific application author with I D one
now I need to delete all his courses so you know where that courses don't remove
range author that courses now I delete the author himself unit I worry
that authors that removed after and finally I need to complete my unit
of work so changes will be saved to the database so you need to work to complete that's how you should use repository and
going to work so you can download the source code stayed on your own and you
have any questions feel free to post them into discussions area in the next
show you how to structure application I hope you enjoy and thank you for
watching
Entity Framework is an implementation of the repository pattern.
Yo dawg, we heard you like repositories, so we put a repository around your repository!
Hi! I'm Mosh, the author of this video. Thanks everyone for sharing your views. I need to clarify a few things that have been misunderstood.
1- I'm neither an advocate of the repository, nor am I against it. If you watch the video carefully, at minute 9 - 10, I clearly explain that you don't necessarily need the repository pattern in every single project. I'm a big believer of simplicity and I clearly outline that in my video.
2- My intention from this video is to show the proper implementation of the repository pattern that clearly solves the problem it is designed for. Many implement the repository pattern by declaring interfaces that return IQueryable, which is no different from using a DbSet in the first place. This is like lipstick on the pig, and adds no values. Some of the arguments in the comments refer to "repository around repository" and I totally agree on this. Plus, a repository should not have a Save or Update method, because sometimes you need to work with multiple repositories in one transaction. Then, which one should be responsible for completing the unit of work and persisting objects? That's why the Save method belongs to the unit of work.
3- It is true that O/RMs or even the underlying DBMSes do not change often. But you shouldn't use repository pattern mainly to address this issue. Instead, think of "separation of concerns". Querying logic, eager loading, joining, etc belong to the data access layer, and when you bring this stuff into your services or presentation layers, you're polluting them with concerns that belong somewhere else. The end result is: fat services or fat controllers. And more importantly, when you look at your unit tests, they look even worse. Perhaps, that's when you should stop for a second, and see if repository pattern can be a solution.
Again, the repository pattern is not needed for every project. But when it is needed, it should be implemented the right way to get the right value out of it.
This past year I developed an application using the Repository Pattern in MVC - Web API2 . I did it because I read on the web that I should and I just didn't know better. I asked this new guy at work if I should use the pattern and he said no. I asked what I should do instead. He said I should do nothing until he could put together a training session on his recommendation. He wouldn't even tell me the name of the pattern. That was in like January of this year. In April I had most of the project done with the Repository Pattern. Due to budget cuts he's not here anymore. He might come back but who knows. Maybe he'll do that training then. ;-)
After the first couple of weeks of development I got a good idea of how the pattern worked. Eventually, it felt so silly. An abstraction from an abstraction so I could maybe someday put in a different abstraction.
I came to the conclusion that EF is close enough to a Repository pattern all by itself that I don't need to construct my own on top of it. Throw in some helper classes and do the work in the Controller and I'm set.
At least that's what I think would happen. <sad snicker>
Apparently I'm the only one here who has switched out ORMs or added new ones.
Next do query objects!
Hey Mosh I really enjoy your videos, this one is really well done, thanks.
The two top comments here are saying that EF is already an implimentation of the repository pattern.
I'm watching the video right now and 5mins in, he actually addresses this specifically. The video is worth watching.