We have a kind of generic repository pattern i quite like at work. There you still implement a repository for each entity, but inherit from the Generic Repository. This way you can always override the generic repository to do entity specific things that the generic repository doesn't provide and you don't have to implement the same methods again and again.
But wouldn't you end up in having too many repositories (per entity) if each of it inherits from a parent class? E.g. imagine if you have repositories that do basic CRUD operations and inherit from a generic repository, you will be left with a lot of potential repositories that has not much to offer since you will also create a service per entity to implement your business logic (using the repository). What are your thoughts @MilanJovanovicTech? How can we avoid this in an architecture like the union one. I understand the principle of reducing code duplication, but it seems to me a bit overkill.
edit: let me clarify by saying what I am talking about below is specific repositories, not generic one. I do completely agree with Milan that having a generic repository alone is a complete waste and just a useless wrapper, but using specific repositories along with a UoW is what I am referring to. Tbh I didn't even realize it's common that people use a generic repo only. ------- Repositories work great if you implement a unitofwork with it, it's a little weird having repositories without a unitofwork for all the reasons you mentioned in the video. The power in repositories in my opinion is re-usability and ease of change/future proofing. What happens if tomorrow EF contains a massive bug or exploit that causes problems, and you need to switch your db querying to a different provider? You will need to re-write a lot of potentially duplicated code across the board, instead of just 1 location. That's the positive side from my perspective, but to each their own. And at the end of the day, there is no one-solution-fits all situation, so do what makes sense for the scenario you are in
Tbh not really. I've had a huge battle with my team against repositories in my current project which unfortunately I've lost due to links to some MS docs from 2012 (where MS was showing repos). 1. If EF has some massive bug than it will get fixed ASAP. Like really ASAP this stuff is used tens of thousands of projects across the globe. You will have far much easier time upgrading the EF Package than rewriting your repositories. Which leaves us with only other valid scenario which is changing ORMs and how likely are you to do that. 2. Also if we are using ORM most likely we are also going some kind of DDD. That means you should only use EF to either retrieve aggregates which are (should) be build using the same method or to make a non tracking query to database. In second scenario what you end up doing is writing a query against the Quarriable which you may need to rewrite in case of an ORM Change.
EF bugs etc was just an example, there could be many reasons causing you to switch out your provider or ORM or whatever you happen to be using. One major thing I can think of is consulting work for example... If let's say you used dapper when you implemented the project, but after handing it off to your customer, their team doesn't like dapper for some reason and they want to use something else. Having a repo in this case makes things much easier to swap out, without risking changing other pieces of code that really don't need changed. The biggest thing here is code duplication/separation. in the chance you need to switch something out, and risk changing code logic that you don't really need to change, when all you really want is to update how you perform a database query. Even if you were to not use a repo pattern, and let's say you create some kind of a factory for your queries to avoid duplication, you're still basically implementing a repo pattern here, nothing's really changed. But like I said, I am NOT against not using repos, there are other drawbacks to using repos, I just don't think the given example is realistic in terms of an implementation without a UoW, which in my opinion is required for a proper repo implementation
Usually, I'm using the Generic repository as a base class, I'm not exposing the AsQueryrable as public. so What I do in your case is I create one Method in orderRepository to get a single item, and in the implementation, I use a Generic repository, but in OrderRepositoy we only see the Insert & Get Single Item, so in my perception, we can't use a generic repository like that, expose all method but it depends on how you design your structure code. like @A alddin said the biggest concern for me is the duplication/separation code, so if you need fast you can work directly in EFContext, but if you need maintenance the code, and in the future maybe you need to adjust the method to do a performance, you can re-write the single item use like (dapper/native command) and in all logic will be changes
I started learning about the Repository pattern design last week and this video put more light on do's and don'ts. Thank you. I also enjoy your newsletters. although some may seem slightly advanced to me, they motivate me to expand my knowledge base.
Add UnitOfWork on top of it and you are fine. It depends how you implement this, and while your example shows that that example is weird to work with (it does work however), it can be adjusted and further improved. That's how building software (and architecture) works.
@@anvogel99 why not ? efCorecontext.Set().add efCoreContext.Set().add and call the save in Unit of work, or you can combine all in a manager class which is a unit of work. efcore eb context already provides a very powerfull generic implementation and a perfect lambda query builder. why should I wrap that perfect wrapper again
If you implement the unit of work than its great again. And you can also implement a repo for all Entities that inherits from the base repo class and specifies the Entity type directly. With this approach you have your repo base methods like add, update, delete and get for example behind your base class and you can keep your Implementation of the e.g. Order Repo clean and add only specific methods to this class. Also what i do is get the db set of the specified entity in the base repo and than you are locked only with the specified set and can't do anything else.
@@MilanJovanovicTech because i want to keep the application as clean as possible. Im also starting to implement ddd as much as possible and this will also help to keep the repos more clean. I use the repos to fully separate the logic. But i have a question for ddd. How to implement aggregates and all this stuff when you work with lists in lists and so on. I have a big entity with many lists in it and other props and many other entities
@@flobuilds Let me understand, to keep thing clean you encapsuate a repository (EF) with units of work in an repository with units of work? How is that clean?
I have worked in projects with already existing databases and usinng the repository pattern saved a lot of time and code. It's not the first way to go for coding but I believe it has it's purposes when needed.
Eh, I’ve found a generic very useful as a base inheritance for the specific repo implementations. Keeps a consistent foundation and behavior that can be cleanly overridden when needed for a particular repo implementation. Also reduces boilerplate.
@@MilanJovanovicTech the specific repo inherits from the generic to reduce boilerplate and keep a base consistency that can be overridden when needed. The reason I don’t use dbcontext directly is mostly for testing, but also for consistency of use as mentioned before and other benefits that you get out of a repo.
Totally agree. It is just a wrapper around an already perfect wrapper like ef core is. Anyway I like using repository pattern and depending on abstractions. In the future you might need to change infrastructure, like for example move to dapper or to any other ORM, so sometimes it can be useful
Handling the EF calls directly in the Application layer seems to go against the Clean Architecture recommendation to handle persistence in the Infrastructure layer? Your videos are always on-point and informative.
Great content! The problem you are trying to show with generic repositories... wouldn"t the same problem surface if you used a non-generic version? Or, is the point of the problem only the way you register it in the DI container? You could specialise your repository and extend it. interface IMyRepository : IRepository { Task SpecialSearch(...) } class MyRepository : IMyRepository { Task SpecialSearch(...) } Then you would register the IMyRepository and the problem would be resolved. Or, with your original implementation you could open up for the Specification Pattern in a search method.
Why if get rid off GetById, GetAll, GetQueryable, and add Specifications to it, and nest it in Unit Of Work? You still need to encapsulate some logick inside repository, but difference between concrete repositories will tend to zero. If make implement them this way will it still sucks?
Great content! But, for example, you didn't call Dispose() for the DbContext. With the repository, this would be centralized and transparent! In some projects, we actually mix Queries with Dapper with persistence made with EF. Would using a Repository be better in these cases?
tbh i only use repository pattern with unit of work. I would have a global save changes method so instead of having save changes for each repository i would only have one and it would be defined in my Unit Of Work Interface. All my methods of the generic repository inside would only do what they are suposse to do which is add update or remove. The responsiblity of saving those changes would be on my unit of work. So i can add a entity but if i don't call save changes on my unit of work it wouldn't save. Some people dislike this way but for me the responsibility to do this would be my service layer which has the responsiblity to make sure the business rules are applied. But this is me im sure u guys might have different ideas
For me, repository ( generic or not ) should not expose IQueryable. The query should be handled within specific repository that inherit from Generic repo... Ie OrderRepository : GenericRepository
I always wondered what is the reason of having getall() method of list type, as in real apps there can be millions of rows, and that thing just loads them in memory
So, what's the cleanest way to encapsulate data access logic instead of having this repository? Making a custom repository inherit from the generic one for the custom/complex scenarios will help in this case? And what if we gonna change the db engine, depending on context directly will push us to many changes in many places, right?
@@MilanJovanovicTech but making specific repository for each command/query will produce many files beside duplication, what do you think? There're specification pattern, looks like a solution? Yes, I might change db engine, may be use non relational db for reading and relational one for writing, what do you think?
Interesting. I've used it in a few projects I've worked on but not just this implementation; instead, I've used it as the base repository for every repository I've created, and then implemented the unit of work pattern to wrap the savechanges method with it.. is that ok?
Tried using the dbcontext directly in a project recently and it was fun till I started writing my unit test it felt like I started wrting more code , I still prefer the write a generic respository with all in include params for joins in queries. Better reuse of code for me than witting specific repository. I mean why repeat myself.
Absolutely agree with you on the "useless wrapper" summary. Been down this path in the past with overzealous architects and its lead to many exceptional cases as app grew in size/complexity.
4:40 would point out that you defined the SaveChangesAsync, but did not use async and await with that method. I do agree that I don't see a benefit in using a generic repository pattern that you demonstrated here.
Even if you're tempted to use generic repository to reduce duplication, please don't. I've been this path, it doesn't lead to a bright future of the app. I have spoken 😃
yeah me too, this isn’t how I implement generic repository, when I have several derived classes I implement unit of work to take care of the transaction
@@Kimo.Codess same idea here, the implementation in video seems weird enough. Not creating concrete derived repository class inherits form the GenericRepository make it mostly impossible to write any specific query related to that repository without uselessly expose IQueryable type from the repository
A generic repository seems to simplify a lot at first sight, however, it has a lot of drawbacks in any avdanced scenario. Mostly it doesn't fit non-CRUD operations well, it defies interface segregation, and is inflexible for custom query conditions. The latter I solve by applying the Query Object or the Specification pattern.
Downside I’ve found to direct EF is testability. Usually leaning on integration tests where it’s moot, but in instances where you do need to use a unit test, dbcontext adds a lot of complexity and pain.
Well I've been using generic repository pattern with unit of work and generic specification pattern (my customized pattern). The issues that you told have all can been handled. Moreover as others have mentioned unit testability increases dramatically with this approach. Also when u need a specific type of query you can create it.
@@MilanJovanovicTech That is the point with your "anti pattern" rant. You do not test the database, you test the consumers of the repository to do the right stuff and you are directly depending on EF Core, which is a maintenance nightmare (Microsoft doesn't give a F*#! about breaking changes). Not defining an interface that decouples desired behavior from the implementation is just a quick & dirty approach. Inversion of Control gives the need to abstract the behavior your system is depending on, if you do not understand this, then maybe you should not create "tutorial" videos. The next thing that is absolutely not addressed in this video is that it is necessary to separate models. Using database models as domain entities and throwing these entitites out of your controllers as json results is not only bad practice, it is just plain wrong in the long run. Did this years ago like everyone else and ran into really ugly bugs because this pattern enforces an anemic domain model and - and this is the worst part - mutable state wich will be changed by some weird service that only exists to encapsulate business logic. This makes testing quite impossible because you not only have to test the happy path, but also all illegal invariants of an entity. This is just impossible because it will lead into an 2^n problem really quick, depending on the complexity (amount of properties) and variants (data types used for these properties). All in all, i would argue that or mappers like EF Core are the anti patterns, but microsofts marketing and the lack of good education of most developers let's people thing that they are somehow "necessary" and make your life "easier", which they just do not do. They bring more complexity and opaqueness of how your system works. Not separating models, not abstracting behavior you depend on and throwing third party libraries throughout your application will lead to unmaintainable, hard extendable and painful to test big balls of mud to be considered as legacy when being developed. Please do not do this. Do not make each layer depend on some third party library and make your layers clean by using the lowest language levels you can. There will always be some dependency like the programming language or framework, but good software architecture will reduce this to a minimum, making your business application easier to extend, easier to test and agnostic from third parties and their weird roadmaps. This is a win in the long run (believe it or not, software systems will run for a long time, once they are finished), and here I am speaking about decades. And nothing is more painful than making a change in a software that was poorly designed.
Me and my colleagues are communicating through code. Someone who is searching for, but not finding a repository for a certain entity, might wonder why, and look up how the entity has been used in other circumstances, and then learn that it is part of an aggregate!
That’s our use case as well indeed. Because we have a guideline to use repo’s rather than dbcontext directly, devs can not easily write entities that shouldn’t be written directly. When they do all the workarounds to do it anyway, then at least it’s easily picked up on in the pull request.
problems with the repository (applied over EF): 1. you always save UoW (context) and thus, repository save does not make sense 2. repos should handle aggregates, not entities 3. not every aggregate needs add or delete (add is necessary to top-level object, rest can be saved via reachability) so the only benefit of a repo would be some shielding from EF, and it had to be done without introducing ambiguities and without ignoring basic definitions of that repo.
Greetings from Bulgaria. Thank you for your time and efforts to create and share those nice tutorials. Regarding GetAll (either Async or not), this can not be serious. If we have 1 millions rows in the DB with 50 columns, some may be nvarchar(max), i.e. spreading across multiple data pages ... !!??? For the number of columns the same thing follows even for GetById. We usually do not want to pull all columns. Both for load's sake and for security. So here come my next concern. Another good and very common practice is to use intermediate VM classes / entities or as some call it DTO. We do not want unload out whole data table to the end user. So ?? We need mapping. Somehow everyone misses to give examples for that case.
This is just an argument about generic repositories. In most cases where you are dealing with so much data, you will write very specific queries that will be optimal from a performance standpoint. You can then decide if you want those to be part of the repository.
I fully agree. When I learned about DDD and repositories, it never occurred to me to create a generic repository . The only real value of a generic repository would be to allow you to separate projects into code that contains all the queries, and the code that has all of the EF Core conversions and dependencies. Then it's easier to migrate to another ORM in the future. Though in practice that's also not fully separated if you have to optimize your queries using techniques specific to EF Core.
The best part is we already have a generic repository in the DbSet 😅 We can just create a few extension methods for generic queries and it should work just fine
Hi Milan nice video. If using specific repos, would you still use UnitOfWork to save changes? Or would each repo be in charge of saving its own changes. Reason I ask: just wondering how you'd use 2 or more specific repos under one single transaction. Ps, I agree with you, it might be a bit unorthodox but using ef core directly is way more pragmatic, and unit/integration testing with ef core is a breeze these days anyway.
Look i used the generic repository but i also created another interface for every entity . So the generic repository for all entity CRUD . But the interface for each entity is inherited from generic repository and i can add more functional actions. You can use unit of work all will work . But is it affects on the memory ??
I totally disagree. You can use the UnitOfWork with the Generic repository to call savechanges. You can also create a regular repository and inherit from the generic to avoid repeating code and use that. You can also create a base service class that calls savechanges automatically on dispose and inherit your service class from that. I have my own implementation of the generic repository with UnitOfWork as explained and it has dramatically reduced the logic I write with absolutely no limitations or issues. I think that the problem of your implementation is that it is designed to be just a wrapper around ef core. A decent implementation is super useful and a productivity booster.
If you're using a 'specific repository' that inherits from the generic one, and the generic repository uses EF Core for example. Why not just use EF Core directly at that point inside the 'specific repository'? If you want to reduce repetition, add the generic methods in the DbContext.
@@MilanJovanovicTech Sure, you could do that. You could find many ways NOT to use a generic repository. Using a generic repo means I don't have to write a specific repo each time when all I need is simple crud on the entity. It's also much cleaner, more readable code. It's also really simple for unit tests. I've also had scenarios where this abstraction allows me to extend certain functionality easily. Sure, everyone has their own preferences and opinions, and you are entitled to your own. I just don't agree with it being labeled an anti-pattern and "Why it sucks" when the advantages are clear, when a complete implementation of the pattern is done. I challenge you to challenge yourself on this, and build your own complete implementation. I enjoy your videos, I just don't agree with you on this.
I used to use generic repository pattern with reflection dependency injector to be able to easily create API endpoints. It also allows to overwrite it with custom implementation
@@MilanJovanovicTech I created extension method for middleware configuration where I retrieve properties form DbContext, iterate over collection and create, register generic repositories. I think it is quite useful as long only EF Core is used as data source provider
Seems like the only issue you talked about is the GetQueryable. Fo this case I have defined it as Task Get(Expression? filter = null, Func? orderBy = null, string includeProperties = ""); which satisfied almost all cases for me.
In c# 8 I think it was we got default interface members so you can put implementations into the Interface you could actually implement all those methods since they are always the same. You could have multiple GetByIds one for Guid and one for Int. Even with generic repositories people are adding methods to do specific queries. For sure returning IQueryable is just not adding value. In my opinion, if you are just looking for a place to "store" your queries because you don't want them in your handlers or endpoints or whatever, there are better ways to do it than to create a repository if you are using EF. The Specification pattern comes to mind, as well as adding Query objects. (basically a class for each query that you might put into a repository). Are you using a repository with DDD and EF?
@@MilanJovanovicTech you mean pass it through DI like this: builder.Services.AddDbContext(options => options.UseSqlServer(conn)); builder.Services.AddScoped(typeof(IGenericRepository), typeof(GenericRepository)); builder.Services.AddScoped();
@@MilanJovanovicTech you mean pass it through DI like this: builder.Services.AddDbContext(options => options.UseSqlServer(conn)); builder.Services.AddScoped(typeof(IGenericRepository), typeof(GenericRepository)); builder.Services.AddScoped();
Isn't the whole point of making repository pattern to make application easily swappable to other communication with database, like pure sql or in memory? Also is it having any benefit for Moq and unit testing?
Hey @MilanJovanovicTech I have an idea that I am eager to know your opinion 1 - create repo interface for every aggregate not every entity but make all of them non-generic 2 - create uow interface too 3 - create one concrete ApplicationDbContext just as you suggested but make it implement all of the above interfaces 4 - inject just needed interfaces (those are relative to aggregates and) to every RequestHandler (or domain sevice objects) in above scenario you don't wrap a thin proxy over entity framework. also your application layer is not dependent to ef core technology. so both schools are covered. what's your opinion?
@@MilanJovanovicTech Nop. I tried to test your idea in a new project. it works perfectly and It seems you are right when we are sure we don't need to change ef.core but who knows if a bounded context representing a micro service needs to change its persistance mechanism in future? I think above suggestion covers both parties. application layer is independent of ef core technoogy and we don't also repeat ourseves over and over in every repo or make a generic wrapper repo.
And one more reason if I use repo pattern is the solution contains web, api and console , so that I add project reference and share use same repo as well as models and service.
The main issue with ef is that it doesn’t allow extending dbsets so that you can properly add or override stuff like security permissions etc. Would love to see your take on securing queries, insert, update, deletes based on claimsprinciple.
@@MilanJovanovicTech effectively. What we do depending upon perf (and ef 8 likely fixes this with pre compile of queries) is either use a TVF that can be inlined and takes the user id as a parameter for all of our get/lists and have a SecureList extension method on every DbSet. (If it is small we use chained linq where clauses that use predicate builder). We do the same for SecureDelete, SecureInsert and SecureUpdate. In the past that got a wrapper around EF core but now I just use extensions. But it still isn’t a great solution because I want my devs to have to work hard to do any of those things without applying security. It should be the default condition that everything has to go. Through the security checks and rare that they don’t. So I see repository like you outlined as what people do to fix that they can’t extend dbset and inject the ClaimsPrincipal and then override all of the methods and create their own insecure ones that require hoops or at least a Boolean of “yes I really mean bypass security.”
what is the best pattern to use then if not repository pattern? I would love a video on this. Also can you make a video using EF core alongside dapper? Like using them hand in hand, using dapper where ef core lacks and using ef core where it makes sense?
Its important to note that there are different repository patterns. With DDD, it is specifically for interacting with Aggregates, which is different than general DB queries. I'm considering calling it something like an 'aggregate store,' to distinguish. The general repository pattern is a big problem.
Hmm.... I wonder did any of you heard about Specification pattern which could be used here instead of that method returning IQueryable? Generic repo has much more sense with it, and Ardalis has quite handy implementation I think...
Im not sure but when I must create a specific query I use to create a new new class that inherits my basic repository then I create a new interface more specific that inherts my IRepository. then I can create all the query that I want in my specific implementation
I believe it is valid to use a pattern as a generic repository but only together with a unit of work abstraction as this may ease the use of different database providers (EfCore based or not) and all this should be only in the infrastructure layer. In a DDD project the domain layer should be more technology agnostic and this includes in-memory cache and linq based development both them normally needed in a generic repository
Insert, update and delete should be in the unit of work. Instead of GetOneById it's better to have GetOneAsync(Expression filter) - here you don't need to know the type of the primary key. Regarding the GetAllAsync. I think it shouldn't be a part of a contract and should be implemented as protected method that returns IQueryable in the base repository class which implements IRepository interface
For the Generic Repository Pattern (without EF Core, I prefer Query builder like sqlkata), I prefer to have a abstract GenericRepository that implements the base CRUD actions. Every methods should also be virtuel. And Just have a CustomerRepository : GenericRepository. Now the CustomerRepository have all the default methods and you can easily add more methods in the CustomerRepository without creating clutter for other entities/repositories. + if you need to different implementation of the GenericRepository, you can just override it. (afcours, also use interfaces)
Generic repository in my previous project are there to DRY the code. It contains functions for general crud. But it is the abstract class. It is inherited by specific-repositories. So all specific-repositories will have all simple methods without copy-paste the code.
I use a different approach when working with repositories. I encapsulate more logic into my repos: so I would have a single method in my repo that selects a customer and adds an order right into the database. I don't like exposing EF Core to other layers of my code, so my services or CQRS stuff only knows about repositories. That way my application becomes more unit testeable. I use a generic repository but it is abstract. All my real repos inherit from base repo and add any new methods specific to a concrete repository, that way I don't expose IQueryable outside of my repo. Generic repo is not a bad thing in the right hands and can help you get rid of some of the boilerplate code
I don't completely agree. We can implement specification patterns to avoid exposing IQueryable from repository. But in some cases we also need to expose the IQueryable outside repositories because GraphQL does the paging, filtering, sorting and even projection if we return an IQueryable from GraphQL queries. How about moving those together? Repositories should take a specification in and return an IQueryable instead of specific things like IEnumerable, List of IAsyncEnumerable. Let the caller do that however they need it.
Thanks for the video Milan. I think Generic repository with EF Core doesn't make much sense. I actually think repository pattern doesn't make much sense with EF Core either. BUT if you're using Dapper that's a whole different story. Then both repository and generic repository basically become a must have and save you a lot of time and trouble.
@@MilanJovanovicTech The repository is pretty much the same as you did in the video without the SaveChanges method. I previously used Dapper.FastCrud to write the methods easier since you can pass in the type of the entity you're querying but it's also possible without FastCrud aswell, it just gets a little bit trickier.
Gen Rep pattern goes well with Unitofwork and as for querable u can make an iquerable method to return an iquerable so i do not understand why its pointless , u dont want teh devs to use the dbcontext anways hence u wrap it and allow only certain methods , also if u need to do generic or custom filtering or some logging of prev and next state in entities if u dont have a gen repo where u will do it ?
I think it depends, in bigger application there you maybe will have more generic I think it's great. But much smaller applications can get rid of it. :)
I have been struggling on use Repo design pattern or not in long time, I come from 10 years+ .net background and few years work experience in spring boot. My thought is very depend the tech stack used and the project scale. EF is good, it is very good, it come from most of need for CRUD, work with Dapper for very complex SQL is perfect match.
yes , I also believe this sometimes trying put everything into project without knowing the purpose of it , and UOW also we can ignore. but I've seen some documentation the repository should not be exposed to IQuearyble, who cares :)
The eternal battle... I agree how you did it is flawed. It works very well when used with Steve Smiths Ardalis Specification package, none of that returning an IQueryable. That plus mediatR gives you excellent separation of concerns. When you want to make it hard for a dev to do the wrong thing, don't take an application dependency on ef. If that is not an issue or concern then go for it. It's all trade offs there is no "right" way and everyone should be doing X, do what works best for your team.
I agree that this specific implementation of a generic repository is bad. And the reason for that is that it is not that generic - it is implemented taking EF implementation in mind. Instead, it should be implemented from a Domain perspective. According to DDD repository is like a list, you can add items, update items, remove items, get items by ID, and retrieve all items. You do not have "SaveChanges" or "AsQueriable" from the domain perspective. Some already mentioned that "SaveChanges" should be part of a unit of work. And queries are not the responsibility of the repository. One should implement specific queries separately in some "Loader" or query classes. Then you could optimize those queries in these special classes. For example, this way you could use EF for repositories and Dapper for queries. Also, the benefit of having a repository pattern (not just a generic repository) compared to direct usage of DB context is that you can abstract different databases away. For example, you might use an SQL database with EF for Products and a document database for Orders.
If you search for "generic repository C#/.NET" - something like this pops up. That's why I used it for the example. What you are talking about is something entirely different, which I very much agree with.
Agree and disagree with this. If an application is simple and has straight forward crud operations then I agree, this would be an overabstraction and worst and misdirection at best. However, when there is a good deal of business logic involved, I like to move all my db code (including all entity searching) away from the business logic layer. So in this instance would create a generic repository pattern for this along with a unit of work implementation. I don't want my business logic knowing anything about the database specifics and I especially don't want to inject a db context into it. I can also mock the repositories for testing. It's all very well to just say 'Oh just use it directly' but you soon get into messy cross cutting concerns without that abstraction. I definitely would not have DB LINQ code anywhere but a repository. Also, why do you insist in using MediatR for everything? Just curious.
This feels more like a poor implementation of SoC than anything. The goal is to isolate business code from the actual persistence mechanism where the repo could be writing to a file or whatever. As soon as you start passing back EF stuff to support 'querying', you've botched the design. No different than if you coupled to an HTTP api to access the verb; abstract that. Your customers almost certainly don't talk about http verbs.
You didn't implement Generic Repository pattern correctly. For all methods just add predicate, include and enableTracking parameters, to make it flexible for any type of queries - then use it. Also you can use Unit of Works.
1. Remove all the methods from IRepository and add one for the specification pattern 2. Add IUnitOfWork interface and implementation + Unit testing is easier + Queries are reusable - Added complexity
100% Agree. And get worse and worse introducing something like IUnitOfWork and IService. And implementation is only passing down and up through layers. Aaand then Big Ball of Mud growing and growing :D
Supposedly you exclude the save changes to be in unit of work and you shouldn't expose the IQueryable from the repository and you should have a repository for every entity that inherits from generic repository and contains the custom methods instead of specifications
I think , if u are damn sure that you will never change your database (from sql to nosql let's say) and EF, then using the generic repository pattern is useless. but this is a beautiful pattern to incorporate multiple databases without changing any code from your application layer.
Out of the DDD world, when we are designing applications with basic crud ops with a lot of entities, Generic Repository along with UoW makes life much easier. Eg: You can make changes to the respective repositories and let UoW handle the "Save changes". This is especially helpful when dealing with multiple entities in a single transaction. But yeah... In DDD, generic repository doesn't fit well.
@@MilanJovanovicTech No difference. In fact, EFCore DbContext uses in-built Unit Of Work. UoW's multi repository operations allows devs to focus more on the domain logics. Again, this opinion supports architecture that is purely CRUD driven with basic verbose APIs. Not DDD.
It's really interesting watching this video after watching the one from Mosh Hamedani (ruclips.net/video/rtXpYpZdOzM/видео.html). However, now I don't know how to proceed since both your videos make sense but they're conflicting. Does it make sense to follow Mosh's method without the generic part?
It's a great combo, but I don't like the UoW idea with repository properties. This video was basically an argument against "generic" repository. I also have a "specific" repository video that aligns nicely with the one from Mosh
@@MilanJovanovicTech In your unit of work you should have access to your derived repositories then along with one save changes method and probably implement IDisposable then you add this unit of work to your service container, when you need to persist data you will inject only the unit of work and the service container will resolve the repositories. So you can now just use the unit of work to interact with the two data models and call the unit of work’s save changes… I hope I’m not confusing you 😅
Several things to be discussed here: - First, don't expose IQueryable in the Interface, it's leaky abstraction and create useless wrapper Then how do we fix the issue? Just create a concrete Repository class that inherits BaseRepository: CustomerRepository: GenericRepository , then write the customer specific query logic in the concrete CustomerRepository, and expose the method to Service/ Application layer to call. By doing this we can be flexible enough, while still taking advantages of GenericRepository (save us a lot of code to implement basic repository operators like GetOne, GetAll, AddOne, AddMany, Delete, Update,.... in any specific repository class that inherits it).We could also consider applying Specification pattern if logics inside the concrete repository tend to be repetitive. Although this is a controversial topic, will we be seeing another video of you to correct this video 🤣
@@MilanJovanovicTech usually all of benefits from using repository pattern: isolated testability, common abstraction for switching orm/ database, exposing ports for Infrastructure's adapters,... plus the benefits of GenericRepository: saving duplicated CRUD code for any CustomerRepostiory/ UserRepository that inherit it.
Every infrastructure has its own set of trade-offs. By presenting only one perspective, you are providing a one-sided view that may not capture the full complexity of the situation. Generalizing based on this limited perspective, such as applying it universally to all cases like a generic repository, overlooks the nuanced considerations and potential variations inherent in different scenarios.
Yah when our team talks iRepo pattern we include the IUnitOfWork pattern in our meaning… will be nice when copilot just generates all the boilerplate code for us… but do feel it gives us good value for tests when needed. And in theory we could switch out our database layer MSSql/Oracle per customer preference
Then what you recommend 😢 if we dont use generic repository pattern.. then which patter i should look for.. please tell me.. 😢 i am junior software developer.. i need your quick suggestions please.
"why not Just use ef Core instead..." .. First: Because not all data comes out of a SQL database, Second: Also Not everyone wants to marry Microsoft products... did you read Clean architecture, or Just talk about IT ;-)? I totally agree with the Point that a generic Repository is no good Idea if Things grow fast. But Sometimes simple CRUD is totally fine when things should be easy and fit in a unified model ("the next scary anti pattern"😂).... Here is my opinion: dont overengineer eveything with ddd paired with clean and keep your scope, Sometimes this is enough! Also thank you for your ideas to this topic❤. Seldomly younger developers care about Software architecture!
@@MilanJovanovicTech Good point, but the tool we are talking about is not simple (EF core). As a driver of a car you dont need to understand whats inside the engine. But as a mechanic you have to solve problems that have to do with engines (or replace the whole damin thing :D). If you install an engine that you dont understand, you could get problems you dont understand. To use EF core is easy at first glance, but hard to master in many ways. What i was pointing at with overengineering was the fact that you say "use EF core instead of a (generic) repository because its easier". But then you (as a developer) depend on another external tool thats maybe not necessary because its more complex than just to have a raw and plain repository that writes SQL against a relational DB. I also like to use EF Core + LINQ because it totally fits into modern language of C# (with declarative approach). But its not easier! It requires knowledge about LINQ, you need to read Logs to see if the SQL performs bad, you need to have a clear Model (not a domain model, but a data model that reflects your db table), you need to know about lazy loading and eager loading, and so on.
@@sotsch9280 "If you install an engine that you dont understand, you could get problems you dont understand." - the same applies for Database engines 😁 No ORM will save you from having to know SQL and how to use a database.
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
We have a kind of generic repository pattern i quite like at work. There you still implement a repository for each entity, but inherit from the Generic Repository. This way you can always override the generic repository to do entity specific things that the generic repository doesn't provide and you don't have to implement the same methods again and again.
That works better
Same here, combined with unit of work so you have the save changes async not in the repository itself.
But wouldn't you end up in having too many repositories (per entity) if each of it inherits from a parent class? E.g. imagine if you have repositories that do basic CRUD operations and inherit from a generic repository, you will be left with a lot of potential repositories that has not much to offer since you will also create a service per entity to implement your business logic (using the repository). What are your thoughts @MilanJovanovicTech? How can we avoid this in an architecture like the union one. I understand the principle of reducing code duplication, but it seems to me a bit overkill.
edit: let me clarify by saying what I am talking about below is specific repositories, not generic one. I do completely agree with Milan that having a generic repository alone is a complete waste and just a useless wrapper, but using specific repositories along with a UoW is what I am referring to. Tbh I didn't even realize it's common that people use a generic repo only.
-------
Repositories work great if you implement a unitofwork with it, it's a little weird having repositories without a unitofwork for all the reasons you mentioned in the video.
The power in repositories in my opinion is re-usability and ease of change/future proofing. What happens if tomorrow EF contains a massive bug or exploit that causes problems, and you need to switch your db querying to a different provider? You will need to re-write a lot of potentially duplicated code across the board, instead of just 1 location. That's the positive side from my perspective, but to each their own.
And at the end of the day, there is no one-solution-fits all situation, so do what makes sense for the scenario you are in
Tbh not really. I've had a huge battle with my team against repositories in my current project which unfortunately I've lost due to links to some MS docs from 2012 (where MS was showing repos).
1. If EF has some massive bug than it will get fixed ASAP. Like really ASAP this stuff is used tens of thousands of projects across the globe. You will have far much easier time upgrading the EF Package than rewriting your repositories. Which leaves us with only other valid scenario which is changing ORMs and how likely are you to do that.
2. Also if we are using ORM most likely we are also going some kind of DDD. That means you should only use EF to either retrieve aggregates which are (should) be build using the same method or to make a non tracking query to database. In second scenario what you end up doing is writing a query against the Quarriable which you may need to rewrite in case of an ORM Change.
EF bugs etc was just an example, there could be many reasons causing you to switch out your provider or ORM or whatever you happen to be using. One major thing I can think of is consulting work for example... If let's say you used dapper when you implemented the project, but after handing it off to your customer, their team doesn't like dapper for some reason and they want to use something else. Having a repo in this case makes things much easier to swap out, without risking changing other pieces of code that really don't need changed.
The biggest thing here is code duplication/separation. in the chance you need to switch something out, and risk changing code logic that you don't really need to change, when all you really want is to update how you perform a database query. Even if you were to not use a repo pattern, and let's say you create some kind of a factory for your queries to avoid duplication, you're still basically implementing a repo pattern here, nothing's really changed.
But like I said, I am NOT against not using repos, there are other drawbacks to using repos, I just don't think the given example is realistic in terms of an implementation without a UoW, which in my opinion is required for a proper repo implementation
The repository pattern won't save you from a DB provider rewrite...
Usually, I'm using the Generic repository as a base class, I'm not exposing the AsQueryrable as public. so What I do in your case is I create one Method in orderRepository to get a single item, and in the implementation, I use a Generic repository, but in OrderRepositoy we only see the Insert & Get Single Item,
so in my perception, we can't use a generic repository like that, expose all method
but it depends on how you design your structure code. like @A alddin said the biggest concern for me is the duplication/separation code,
so if you need fast you can work directly in EFContext, but if you need maintenance the code, and in the future maybe you need to adjust the method to do a performance, you can re-write the single item use like (dapper/native command) and in all logic will be changes
I started learning about the Repository pattern design last week and this video put more light on do's and don'ts. Thank you. I also enjoy your newsletters. although some may seem slightly advanced to me, they motivate me to expand my knowledge base.
You're very welcome!
Add UnitOfWork on top of it and you are fine. It depends how you implement this, and while your example shows that that example is weird to work with (it does work however), it can be adjusted and further improved. That's how building software (and architecture) works.
There's no way to make this work 😅 Either go the Specific repository route, or just use EF Core
@@MilanJovanovicTech
Generic repos are totally fine from my experience. It can look like:
_repoA.Add(a);
_repoB.Delete(b);
_unitOfWork.Save();
@@anvogel99 exactly like this
@@MilanJovanovicTech well.. A lot of projects use a unit of work, its pretty common. Its easy to combine with the aggregate pattern for example
@@anvogel99
why not ?
efCorecontext.Set().add
efCoreContext.Set().add
and call the save in Unit of work, or you can combine all in a manager class which is a unit of work.
efcore eb context already provides a very powerfull generic implementation and a perfect lambda query builder. why should I wrap that perfect wrapper again
If you implement the unit of work than its great again. And you can also implement a repo for all Entities that inherits from the base repo class and specifies the Entity type directly. With this approach you have your repo base methods like add, update, delete and get for example behind your base class and you can keep your Implementation of the e.g. Order Repo clean and add only specific methods to this class. Also what i do is get the db set of the specified entity in the base repo and than you are locked only with the specified set and can't do anything else.
Why not just use EF Core at that point since it offers all of that without an abstraction?
@@MilanJovanovicTech because i want to keep the application as clean as possible. Im also starting to implement ddd as much as possible and this will also help to keep the repos more clean. I use the repos to fully separate the logic. But i have a question for ddd. How to implement aggregates and all this stuff when you work with lists in lists and so on. I have a big entity with many lists in it and other props and many other entities
I guess because we've learned about the importance of inversion of control, clean architecture, interface segregation etc
@@flobuilds Let me understand, to keep thing clean you encapsuate a repository (EF) with units of work in an repository with units of work? How is that clean?
I have worked in projects with already existing databases and usinng the repository pattern saved a lot of time and code. It's not the first way to go for coding but I believe it has it's purposes when needed.
Database-first is a good argument for using it
Eh, I’ve found a generic very useful as a base inheritance for the specific repo implementations. Keeps a consistent foundation and behavior that can be cleanly overridden when needed for a particular repo implementation. Also reduces boilerplate.
But what's the value of a generic base class in a specific repo vs. just using EF Core?
@@MilanJovanovicTech the specific repo inherits from the generic to reduce boilerplate and keep a base consistency that can be overridden when needed. The reason I don’t use dbcontext directly is mostly for testing, but also for consistency of use as mentioned before and other benefits that you get out of a repo.
@@pdevito testability is important, I was agreeing in the video but I remember testing.
Totally agree. It is just a wrapper around an already perfect wrapper like ef core is. Anyway I like using repository pattern and depending on abstractions. In the future you might need to change infrastructure, like for example move to dapper or to any other ORM, so sometimes it can be useful
That's not really changing infrastructure. Just changing data access mechanism.
@@MilanJovanovicTech yep, that's what I meant
I read some article talk about that, and I like a words:( avoid abstraction of abstraction )
Handling the EF calls directly in the Application layer seems to go against the Clean Architecture recommendation to handle persistence in the Infrastructure layer? Your videos are always on-point and informative.
It does go against CA directive. I will sometimes be pragmatic and break this constraint.
Great content!
The problem you are trying to show with generic repositories... wouldn"t the same problem surface if you used a non-generic version?
Or, is the point of the problem only the way you register it in the DI container?
You could specialise your repository and extend it.
interface IMyRepository : IRepository
{
Task SpecialSearch(...)
}
class MyRepository : IMyRepository
{
Task SpecialSearch(...)
}
Then you would register the IMyRepository and the problem would be resolved.
Or, with your original implementation you could open up for the Specification Pattern in a search method.
That's a specific repository with a generic base class. Why not just use a Specific repository with EF Core in the implementation?
What about combining the generic repo with the specification pattern?
That's even more of a mess 😅
Could you elaborate?
Why if get rid off GetById, GetAll, GetQueryable, and add Specifications to it, and nest it in Unit Of Work? You still need to encapsulate some logick inside repository, but difference between concrete repositories will tend to zero. If make implement them this way will it still sucks?
It will suck less 😁
Great content! But, for example, you didn't call Dispose() for the DbContext. With the repository, this would be centralized and transparent!
In some projects, we actually mix Queries with Dapper with persistence made with EF. Would using a Repository be better in these cases?
The runtime will take care of disposing
tbh i only use repository pattern with unit of work. I would have a global save changes method so instead of having save changes for each repository i would only have one and it would be defined in my Unit Of Work Interface. All my methods of the generic repository inside would only do what they are suposse to do which is add update or remove. The responsiblity of saving those changes would be on my unit of work. So i can add a entity but if i don't call save changes on my unit of work it wouldn't save. Some people dislike this way but for me the responsibility to do this would be my service layer which has the responsiblity to make sure the business rules are applied. But this is me im sure u guys might have different ideas
At that point I'd just the specific repository, which is better imo
Totally agree with you. I wrote an article 2 years ago on Medium "Combining repository pattern and unit of work using EntityFramework Core"
Can you add a link?
For me, repository ( generic or not ) should not expose IQueryable. The query should be handled within specific repository that inherit from Generic repo... Ie OrderRepository : GenericRepository
Then you're not doing a generic repository, but a SPECIFIC one. With a generic base class.
I can't like this enough. Including IQueryable would trigger a "Requested Changes" action from me during a PR review. :)
That's the whole point. there is no use of a generic repository if you are going to expose IQueryable. It would be a useless wrapper
I always wondered what is the reason of having getall() method of list type, as in real apps there can be millions of rows, and that thing just loads them in memory
Hopefully you won't use it on a large table 🤣
So, what's the cleanest way to encapsulate data access logic instead of having this repository?
Making a custom repository inherit from the generic one for the custom/complex scenarios will help in this case?
And what if we gonna change the db engine, depending on context directly will push us to many changes in many places, right?
Make the repository specific, and only return what you need.
Are you ever going to change the DB engine, really?
@@MilanJovanovicTech but making specific repository for each command/query will produce many files beside duplication, what do you think?
There're specification pattern, looks like a solution?
Yes, I might change db engine, may be use non relational db for reading and relational one for writing, what do you think?
Wonderful to find this video, finally someone with common sense and an explanation straight to the point. Thank you!!!
I'm glad you enjoyed it, Emanuel :)
Hello Milan, I have a question please.
Why Insert/Update/Delete methods are made sync not async ?
Because they don't call the database
Interesting.
I've used it in a few projects I've worked on but not just this implementation;
instead, I've used it as the base repository for every repository I've created, and then implemented the unit of work pattern to wrap the savechanges method with it.. is that ok?
That's all right!
Tried using the dbcontext directly in a project recently and it was fun till I started writing my unit test it felt like I started wrting more code , I still prefer the write a generic respository with all in include params for joins in queries. Better reuse of code for me than witting specific repository. I mean why repeat myself.
There isn't a lot of value in unit testing data access logic
Agreed - I've regretted it each time that I implemented the generic repository pattern. It felt pointless in exactly the way that you described.
You understand!
Absolutely agree with you on the "useless wrapper" summary. Been down this path in the past with overzealous architects and its lead to many exceptional cases as app grew in size/complexity.
I also hard to learn that the hard way
4:40 would point out that you defined the SaveChangesAsync, but did not use async and await with that method.
I do agree that I don't see a benefit in using a generic repository pattern that you demonstrated here.
Did you even hear the sentence after that? 😅
@@MilanJovanovicTech Nah. Visual learner
Even if you're tempted to use generic repository to reduce duplication, please don't. I've been this path, it doesn't lead to a bright future of the app. I have spoken 😃
I couldn't agree more
I'd like to know more about this, I currently use it as abstract base class with virtual methods which then typed repositories inherit from
yeah me too, this isn’t how I implement generic repository, when I have several derived classes I implement unit of work to take care of the transaction
@@Kimo.Codess same idea here, the implementation in video seems weird enough. Not creating concrete derived repository class inherits form the GenericRepository make it mostly impossible to write any specific query related to that repository without uselessly expose IQueryable type from the repository
@@carmineos same, works perfect.
A generic repository seems to simplify a lot at first sight, however, it has a lot of drawbacks in any avdanced scenario. Mostly it doesn't fit non-CRUD operations well, it defies interface segregation, and is inflexible for custom query conditions. The latter I solve by applying the Query Object or the Specification pattern.
I'm enjoying more and more using EF Core directly
Downside I’ve found to direct EF is testability. Usually leaning on integration tests where it’s moot, but in instances where you do need to use a unit test, dbcontext adds a lot of complexity and pain.
@@pdevitoi think you can create and use interface IApplicationDbContext. In that way, it is easy to mock and unit test will be easier to implement.
Well I've been using generic repository pattern with unit of work and generic specification pattern (my customized pattern). The issues that you told have all can been handled. Moreover as others have mentioned unit testability increases dramatically with this approach. Also when u need a specific type of query you can create it.
What is the value of unit testing the DB?
@@MilanJovanovicTech That is the point with your "anti pattern" rant. You do not test the database, you test the consumers of the repository to do the right stuff and you are directly depending on EF Core, which is a maintenance nightmare (Microsoft doesn't give a F*#! about breaking changes). Not defining an interface that decouples desired behavior from the implementation is just a quick & dirty approach. Inversion of Control gives the need to abstract the behavior your system is depending on, if you do not understand this, then maybe you should not create "tutorial" videos.
The next thing that is absolutely not addressed in this video is that it is necessary to separate models. Using database models as domain entities and throwing these entitites out of your controllers as json results is not only bad practice, it is just plain wrong in the long run. Did this years ago like everyone else and ran into really ugly bugs because this pattern enforces an anemic domain model and - and this is the worst part - mutable state wich will be changed by some weird service that only exists to encapsulate business logic. This makes testing quite impossible because you not only have to test the happy path, but also all illegal invariants of an entity. This is just impossible because it will lead into an 2^n problem really quick, depending on the complexity (amount of properties) and variants (data types used for these properties).
All in all, i would argue that or mappers like EF Core are the anti patterns, but microsofts marketing and the lack of good education of most developers let's people thing that they are somehow "necessary" and make your life "easier", which they just do not do. They bring more complexity and opaqueness of how your system works.
Not separating models, not abstracting behavior you depend on and throwing third party libraries throughout your application will lead to unmaintainable, hard extendable and painful to test big balls of mud to be considered as legacy when being developed.
Please do not do this. Do not make each layer depend on some third party library and make your layers clean by using the lowest language levels you can. There will always be some dependency like the programming language or framework, but good software architecture will reduce this to a minimum, making your business application easier to extend, easier to test and agnostic from third parties and their weird roadmaps. This is a win in the long run (believe it or not, software systems will run for a long time, once they are finished), and here I am speaking about decades. And nothing is more painful than making a change in a software that was poorly designed.
One way they are useful is to restrict them to only accept certain types of entities, eg. Aggregate Roots only. What's your view on that?
I get the argument. But not much value in that - you're still the one writing the code 🤔
Me and my colleagues are communicating through code. Someone who is searching for, but not finding a repository for a certain entity, might wonder why, and look up how the entity has been used in other circumstances, and then learn that it is part of an aggregate!
That’s our use case as well indeed. Because we have a guideline to use repo’s rather than dbcontext directly, devs can not easily write entities that shouldn’t be written directly. When they do all the workarounds to do it anyway, then at least it’s easily picked up on in the pull request.
problems with the repository (applied over EF):
1. you always save UoW (context) and thus, repository save does not make sense
2. repos should handle aggregates, not entities
3. not every aggregate needs add or delete (add is necessary to top-level object, rest can be saved via reachability)
so the only benefit of a repo would be some shielding from EF, and it had to be done without introducing ambiguities and without ignoring basic definitions of that repo.
It's not perfect, but it can be useful
Since you use the customer and order repository, should you not have an unitofwork for the work being done?
We would have it, typically
What if all my repositories have common methods only (0 specific methods). In this case what is a better option than the Generic repository pattern?
If that's the case, why even use a repository. Just use EF
Greetings from Bulgaria. Thank you for your time and efforts to create and share those nice tutorials.
Regarding GetAll (either Async or not), this can not be serious. If we have 1 millions rows in the DB with 50 columns, some may be nvarchar(max), i.e. spreading across multiple data pages ... !!???
For the number of columns the same thing follows even for GetById. We usually do not want to pull all columns. Both for load's sake and for security. So here come my next concern.
Another good and very common practice is to use intermediate VM classes / entities or as some call it DTO. We do not want unload out whole data table to the end user. So ?? We need mapping. Somehow everyone misses to give examples for that case.
This is just an argument about generic repositories. In most cases where you are dealing with so much data, you will write very specific queries that will be optimal from a performance standpoint. You can then decide if you want those to be part of the repository.
doesnt the db context already implement unit of work and repository pattern?
It does
I fully agree. When I learned about DDD and repositories, it never occurred to me to create a generic repository .
The only real value of a generic repository would be to allow you to separate projects into code that contains all the queries, and the code that has all of the EF Core conversions and dependencies. Then it's easier to migrate to another ORM in the future. Though in practice that's also not fully separated if you have to optimize your queries using techniques specific to EF Core.
The best part is we already have a generic repository in the DbSet 😅
We can just create a few extension methods for generic queries and it should work just fine
Hi Milan nice video.
If using specific repos, would you still use UnitOfWork to save changes? Or would each repo be in charge of saving its own changes.
Reason I ask: just wondering how you'd use 2 or more specific repos under one single transaction.
Ps,
I agree with you, it might be a bit unorthodox but using ef core directly is way more pragmatic, and unit/integration testing with ef core is a breeze these days anyway.
Yes, I'd use UnitOfWork in that case
I've seen generic repositories using T or TEntity... what's the difference, if any, and which is the best to use for generics?
No difference
Look i used the generic repository but i also created another interface for every entity .
So the generic repository for all entity CRUD .
But the interface for each entity is inherited from generic repository and i can add more functional actions. You can use unit of work all will work .
But is it affects on the memory ??
How does Generic Repository as a base class differ from just using EF Core?
@@MilanJovanovicTech the generic repository is an interface.
And in the IServiceCollection i dont use the generic , i use the entity interface
the Repository interface, makes it easier to mock out the db context?
You can also mock EF Core?
Tell us how!
I totally disagree. You can use the UnitOfWork with the Generic repository to call savechanges. You can also create a regular repository and inherit from the generic to avoid repeating code and use that. You can also create a base service class that calls savechanges automatically on dispose and inherit your service class from that. I have my own implementation of the generic repository with UnitOfWork as explained and it has dramatically reduced the logic I write with absolutely no limitations or issues. I think that the problem of your implementation is that it is designed to be just a wrapper around ef core. A decent implementation is super useful and a productivity booster.
If you're using a 'specific repository' that inherits from the generic one, and the generic repository uses EF Core for example.
Why not just use EF Core directly at that point inside the 'specific repository'?
If you want to reduce repetition, add the generic methods in the DbContext.
@@MilanJovanovicTech
Sure, you could do that. You could find many ways NOT to use a generic repository. Using a generic repo means I don't have to write a specific repo each time when all I need is simple crud on the entity. It's also much cleaner, more readable code. It's also really simple for unit tests. I've also had scenarios where this abstraction allows me to extend certain functionality easily. Sure, everyone has their own preferences and opinions, and you are entitled to your own. I just don't agree with it being labeled an anti-pattern and "Why it sucks" when the advantages are clear, when a complete implementation of the pattern is done. I challenge you to challenge yourself on this, and build your own complete implementation. I enjoy your videos, I just don't agree with you on this.
I used to use generic repository pattern with reflection dependency injector to be able to easily create API endpoints. It also allows to overwrite it with custom implementation
How does that work?
@@MilanJovanovicTech I created extension method for middleware configuration where I retrieve properties form DbContext, iterate over collection and create, register generic repositories. I think it is quite useful as long only EF Core is used as data source provider
Seems like the only issue you talked about is the GetQueryable. Fo this case I have defined it as Task Get(Expression? filter = null, Func? orderBy = null, string includeProperties = ""); which satisfied almost all cases for me.
Great, now you've got a method that's far more complicated to work with than LINQ
Hi Milan! What theme color that you are using?
VS Dark Theme + ReSharper color highlighting
Thank you so much
In c# 8 I think it was we got default interface members so you can put implementations into the Interface you could actually implement all those methods since they are always the same. You could have multiple GetByIds one for Guid and one for Int.
Even with generic repositories people are adding methods to do specific queries. For sure returning IQueryable is just not adding value.
In my opinion, if you are just looking for a place to "store" your queries because you don't want them in your handlers or endpoints or whatever, there are better ways to do it than to create a repository if you are using EF. The Specification pattern comes to mind, as well as adding Query objects. (basically a class for each query that you might put into a repository).
Are you using a repository with DDD and EF?
I like the "specific repository" that just exposes the methods needed, and under the hood uses EF Core in the implementing class
How can I inject also the dbcontex and so not have into the GenericRepository class. you have an example? Thx Stefano
Just use the DbContext directly then?
@@MilanJovanovicTech you mean pass it through DI like this:
builder.Services.AddDbContext(options =>
options.UseSqlServer(conn));
builder.Services.AddScoped(typeof(IGenericRepository), typeof(GenericRepository));
builder.Services.AddScoped();
@@MilanJovanovicTech you mean pass it through DI like this:
builder.Services.AddDbContext(options =>
options.UseSqlServer(conn));
builder.Services.AddScoped(typeof(IGenericRepository), typeof(GenericRepository));
builder.Services.AddScoped();
You may use Specification Pattern together with Repository Pattern, that's the one I am using.
With or without a generic repository?
@@MilanJovanovicTech , with Generic Repository. I have the basic CRUD operations and use my services as my unit of work.
Isn't the whole point of making repository pattern to make application easily swappable to other communication with database, like pure sql or in memory? Also is it having any benefit for Moq and unit testing?
There's benefit for unit testing, yes. But is there value in unit testing the DB?
Why dont you use an async method for insert, update and delete?
Because they don't do anything - just add the entity to the ChangeTracker
Hey @MilanJovanovicTech
I have an idea that I am eager to know your opinion
1 - create repo interface for every aggregate not every entity but make all of them non-generic
2 - create uow interface too
3 - create one concrete ApplicationDbContext just as you suggested but make it implement all of the above interfaces
4 - inject just needed interfaces (those are relative to aggregates and) to every RequestHandler (or domain sevice objects)
in above scenario you don't wrap a thin proxy over entity framework. also your application layer is not dependent to ef core technology. so both schools are covered.
what's your opinion?
Do you have a demo implementation?
@@MilanJovanovicTech Nop. I tried to test your idea in a new project. it works perfectly and It seems you are right when we are sure we don't need to change ef.core but who knows if a bounded context representing a micro service needs to change its persistance mechanism in future?
I think above suggestion covers both parties. application layer is independent of ef core technoogy and we don't also repeat ourseves over and over in every repo or make a generic wrapper repo.
And one more reason if I use repo pattern is the solution contains web, api and console , so that I add project reference and share use same repo as well as models and service.
I like it for testability
The main issue with ef is that it doesn’t allow extending dbsets so that you can properly add or override stuff like security permissions etc.
Would love to see your take on securing queries, insert, update, deletes based on claimsprinciple.
Row Level Security? 🤔
@@MilanJovanovicTech effectively. What we do depending upon perf (and ef 8 likely fixes this with pre compile of queries) is either use a TVF that can be inlined and takes the user id as a parameter for all of our get/lists and have a SecureList extension method on every DbSet. (If it is small we use chained linq where clauses that use predicate builder).
We do the same for SecureDelete, SecureInsert and SecureUpdate.
In the past that got a wrapper around EF core but now I just use extensions. But it still isn’t a great solution because I want my devs to have to work hard to do any of those things without applying security. It should be the default condition that everything has to go. Through the security checks and rare that they don’t.
So I see repository like you outlined as what people do to fix that they can’t extend dbset and inject the ClaimsPrincipal and then override all of the methods and create their own insecure ones that require hoops or at least a Boolean of “yes I really mean bypass security.”
what is the best pattern to use then if not repository pattern? I would love a video on this. Also can you make a video using EF core alongside dapper? Like using them hand in hand, using dapper where ef core lacks and using ef core where it makes sense?
Here you go: ruclips.net/video/PxxZcTBYi34/видео.html
Its important to note that there are different repository patterns. With DDD, it is specifically for interacting with Aggregates, which is different than general DB queries. I'm considering calling it something like an 'aggregate store,' to distinguish.
The general repository pattern is a big problem.
I just called it 'specific repository' and I think that's a fine approach, since you're only exposing aggregates
Hmm.... I wonder did any of you heard about Specification pattern which could be used here instead of that method returning IQueryable? Generic repo has much more sense with it, and Ardalis has quite handy implementation I think...
I talked about the Specification pattern before
@@MilanJovanovicTech need to catch it up :) thanks :)
Im not sure but when I must create a specific query I use to create a new new class that inherits my basic repository then I create a new interface more specific that inherts my IRepository. then I can create all the query that I want in my specific implementation
That's pretty much the Specific repository pattern, with a base class... At that point why not just use EF Core directly in the Specific repository?
I believe it is valid to use a pattern as a generic repository but only together with a unit of work abstraction as this may ease the use of different database providers (EfCore based or not) and all this should be only in the infrastructure layer. In a DDD project the domain layer should be more technology agnostic and this includes in-memory cache and linq based development both them normally needed in a generic repository
If you ever try to couple more than one DB provider in a single unit of work, you're in for a world of hurt
is this not useful when mixing EFcore and Dapper for instance?
It could be, but you'll run into issues with Identity Map / Change Tracking support
Insert, update and delete should be in the unit of work. Instead of GetOneById it's better to have GetOneAsync(Expression filter) - here you don't need to know the type of the primary key. Regarding the GetAllAsync. I think it shouldn't be a part of a contract and should be implemented as protected method that returns IQueryable in the base repository class which implements IRepository interface
I like the suggestions!
@@MilanJovanovicTech Thank you 😉
For the Generic Repository Pattern (without EF Core, I prefer Query builder like sqlkata), I prefer to have a abstract GenericRepository that implements the base CRUD actions. Every methods should also be virtuel. And Just have a CustomerRepository : GenericRepository. Now the CustomerRepository have all the default methods and you can easily add more methods in the CustomerRepository without creating clutter for other entities/repositories. + if you need to different implementation of the GenericRepository, you can just override it. (afcours, also use interfaces)
I'll check out Sqlkata, sounds interesting
How to use SQL Sequence NEXT VALUE FOR .Net API and Entity Framework???
Thanks in advance.
Haven't tried it
@@MilanJovanovicTech
Can you make a video regarding SQL Sequence and EF?
Generic repository in my previous project are there to DRY the code. It contains functions for general crud. But it is the abstract class. It is inherited by specific-repositories. So all specific-repositories will have all simple methods without copy-paste the code.
I've seen that idea float around, I might explore it in another video
I use a different approach when working with repositories. I encapsulate more logic into my repos: so I would have a single method in my repo that selects a customer and adds an order right into the database. I don't like exposing EF Core to other layers of my code, so my services or CQRS stuff only knows about repositories. That way my application becomes more unit testeable. I use a generic repository but it is abstract. All my real repos inherit from base repo and add any new methods specific to a concrete repository, that way I don't expose IQueryable outside of my repo. Generic repo is not a bad thing in the right hands and can help you get rid of some of the boilerplate code
That approach makes sense. Maybe I need to record another video?
@@MilanJovanovicTech maybe
I don't completely agree. We can implement specification patterns to avoid exposing IQueryable from repository.
But in some cases we also need to expose the IQueryable outside repositories because GraphQL does the paging, filtering, sorting and even projection if we return an IQueryable from GraphQL queries.
How about moving those together?
Repositories should take a specification in and return an IQueryable instead of specific things like IEnumerable, List of IAsyncEnumerable. Let the caller do that however they need it.
What's the point of Specification then if you'll just return IQueryable? 🤦♂️
Thanks for the video Milan.
I think Generic repository with EF Core doesn't make much sense. I actually think repository pattern doesn't make much sense with EF Core either.
BUT if you're using Dapper that's a whole different story. Then both repository and generic repository basically become a must have and save you a lot of time and trouble.
How would you do generic repository with Dapper?
@@MilanJovanovicTech The repository is pretty much the same as you did in the video without the SaveChanges method. I previously used Dapper.FastCrud to write the methods easier since you can pass in the type of the entity you're querying but it's also possible without FastCrud aswell, it just gets a little bit trickier.
Gen Rep pattern goes well with Unitofwork and as for querable u can make an iquerable method to return an iquerable so i do not understand why its pointless , u dont want teh devs to use the dbcontext anways hence u wrap it and allow only certain methods , also if u need to do generic or custom filtering or some logging of prev and next state in entities if u dont have a gen repo where u will do it ?
What are you adding on top of EF with the wrapper? Nothing... Hence why it's pointless
Man, I asked myself this very question. Why use a generic, which ends up being a pointless wrapper, truly spot on.
I like the repository, but not when it's done like this
@@MilanJovanovicTech I just saw it implemented as “clean architecture”, don’t know what to think at this point.
I think it depends, in bigger application there you maybe will have more generic I think it's great. But much smaller applications can get rid of it. :)
Probably the opposite of that makes sense
I have been struggling on use Repo design pattern or not in long time, I come from 10 years+ .net background and few years work experience in spring boot. My thought is very depend the tech stack used and the project scale.
EF is good, it is very good, it come from most of need for CRUD, work with Dapper for very complex SQL is perfect match.
It's a topic that will forever be love/hate for .NET devs
yes , I also believe this sometimes trying put everything into project without knowing the purpose of it , and UOW also we can ignore. but I've seen some documentation the repository should not be exposed to IQuearyble, who cares :)
I've seen worse implementations than this one in the wild
The eternal battle... I agree how you did it is flawed. It works very well when used with Steve Smiths Ardalis Specification package, none of that returning an IQueryable. That plus mediatR gives you excellent separation of concerns.
When you want to make it hard for a dev to do the wrong thing, don't take an application dependency on ef. If that is not an issue or concern then go for it. It's all trade offs there is no "right" way and everyone should be doing X, do what works best for your team.
I covered specification pattern in another video, no beef with it
I agree that this specific implementation of a generic repository is bad. And the reason for that is that it is not that generic - it is implemented taking EF implementation in mind. Instead, it should be implemented from a Domain perspective. According to DDD repository is like a list, you can add items, update items, remove items, get items by ID, and retrieve all items. You do not have "SaveChanges" or "AsQueriable" from the domain perspective.
Some already mentioned that "SaveChanges" should be part of a unit of work. And queries are not the responsibility of the repository. One should implement specific queries separately in some "Loader" or query classes. Then you could optimize those queries in these special classes. For example, this way you could use EF for repositories and Dapper for queries.
Also, the benefit of having a repository pattern (not just a generic repository) compared to direct usage of DB context is that you can abstract different databases away. For example, you might use an SQL database with EF for Products and a document database for Orders.
If you search for "generic repository C#/.NET" - something like this pops up. That's why I used it for the example.
What you are talking about is something entirely different, which I very much agree with.
I am using generic repository pattern on my current project, and I regret that I cannot get rid of it now.
It's never too late to start
Agree and disagree with this. If an application is simple and has straight forward crud operations then I agree, this would be an overabstraction and worst and misdirection at best. However, when there is a good deal of business logic involved, I like to move all my db code (including all entity searching) away from the business logic layer. So in this instance would create a generic repository pattern for this along with a unit of work implementation. I don't want my business logic knowing anything about the database specifics and I especially don't want to inject a db context into it. I can also mock the repositories for testing. It's all very well to just say 'Oh just use it directly' but you soon get into messy cross cutting concerns without that abstraction. I definitely would not have DB LINQ code anywhere but a repository. Also, why do you insist in using MediatR for everything? Just curious.
There's always extension methods, static classes to solve duplication.
I like the benefits I get with MediatR. What else?
EF already implements the repository and unit of work patterns. You don’t need to implement them again on top of what is already there.
Unless you do
Generic Repository + Unit of Work + Query Specification together make a powerful, fancy, and useful combination.
When would you consider it too much?
@@MilanJovanovicTech When I choose N-Tire.
This feels more like a poor implementation of SoC than anything. The goal is to isolate business code from the actual persistence mechanism where the repo could be writing to a file or whatever. As soon as you start passing back EF stuff to support 'querying', you've botched the design. No different than if you coupled to an HTTP api to access the verb; abstract that. Your customers almost certainly don't talk about http verbs.
It should. This is how a lot of people do it.
@@MilanJovanovicTech Yeah, that's just cargo culting. Not ever layer of indirection actually brings value, but they always bring complexity.
You didn't implement Generic Repository pattern correctly. For all methods just add predicate, include and enableTracking parameters, to make it flexible for any type of queries - then use it. Also you can use Unit of Works.
Why not just use EF Core if you'll go through all that trouble?
Generic repository+specification+mapper work fine for common scenaios
As if the generic repository wasn't enough, you'd slap a Specification on it? 😅
1. Remove all the methods from IRepository and add one for the specification pattern
2. Add IUnitOfWork interface and implementation
+ Unit testing is easier
+ Queries are reusable
- Added complexity
@@z0n_ Or move save changes to IAppDbContext
100% Agree. And get worse and worse introducing something like IUnitOfWork and IService. And implementation is only passing down and up through layers. Aaand then Big Ball of Mud growing and growing :D
IService 🤮🤮🤮
Yes! Finally. You have a negative viewpoint about something! Great video too!
Should I talk more about things I disagree with? 🤣
awesome video! thanks!
Glad you enjoyed it!
In my opinion Dapper + Repository pattern is very great tool. Just will leave this opinion here :)
I'll agree. But you probably don't make it a generic repo with Dapper
Supposedly you exclude the save changes to be in unit of work and you shouldn't expose the IQueryable from the repository and you should have a repository for every entity that inherits from generic repository and contains the custom methods instead of specifications
Supposedly
I'll add to the anti-pattern that GetAll method. What happens when someone decides to fetch the whole database with it!!!
Things blow up
I think , if u are damn sure that you will never change your database (from sql to nosql let's say) and EF, then using the generic repository pattern is useless. but this is a beautiful pattern to incorporate multiple databases without changing any code from your application layer.
Shouldn't we treat different databases... differently? They're powerful tools. If we abstract too much, we risk losing all these awesome features.
that's true indeed.
Out of the DDD world, when we are designing applications with basic crud ops with a lot of entities, Generic Repository along with UoW makes life much easier.
Eg: You can make changes to the respective repositories and let UoW handle the "Save changes". This is especially helpful when dealing with multiple entities in a single transaction.
But yeah... In DDD, generic repository doesn't fit well.
How does Generic Repository as a base class differ from just using EF Core?
@@MilanJovanovicTech No difference.
In fact, EFCore DbContext uses in-built Unit Of Work. UoW's multi repository operations allows devs to focus more on the domain logics.
Again, this opinion supports architecture that is purely CRUD driven with basic verbose APIs. Not DDD.
EF itself implements repository pattern basically.
Yup
It's really interesting watching this video after watching the one from Mosh Hamedani (ruclips.net/video/rtXpYpZdOzM/видео.html). However, now I don't know how to proceed since both your videos make sense but they're conflicting. Does it make sense to follow Mosh's method without the generic part?
It's a great combo, but I don't like the UoW idea with repository properties. This video was basically an argument against "generic" repository. I also have a "specific" repository video that aligns nicely with the one from Mosh
@@MilanJovanovicTech Thanks. I'll check out your other video. What's wrong with repository properties in UoW?
Repository pattern with multiple derived classes work best with unit of work you know 💁♂️
How so?
@@MilanJovanovicTech In your unit of work you should have access to your derived repositories then along with one save changes method and probably implement IDisposable then you add this unit of work to your service container, when you need to persist data you will inject only the unit of work and the service container will resolve the repositories. So you can now just use the unit of work to interact with the two data models and call the unit of work’s save changes… I hope I’m not confusing you 😅
I'm dealing with multiple generic repositories with multiple DbContexts.
Oh crap
@@MilanJovanovicTech 🤣
I would argue that a DbSet is already a generic repository
Yes
Several things to be discussed here:
- First, don't expose IQueryable in the Interface, it's leaky abstraction and create useless wrapper
Then how do we fix the issue?
Just create a concrete Repository class that inherits BaseRepository: CustomerRepository: GenericRepository , then write the customer specific query logic in the concrete CustomerRepository, and expose the method to Service/ Application layer to call. By doing this we can be flexible enough, while still taking advantages of GenericRepository (save us a lot of code to implement basic repository operators like GetOne, GetAll, AddOne, AddMany, Delete, Update,.... in any specific repository class that inherits it).We could also consider applying Specification pattern if logics inside the concrete repository tend to be repetitive.
Although this is a controversial topic, will we be seeing another video of you to correct this video 🤣
What's the added value of using GenericRepository vs. using DbContext.Customers?
@@MilanJovanovicTech usually all of benefits from using repository pattern: isolated testability, common abstraction for switching orm/ database, exposing ports for Infrastructure's adapters,... plus the benefits of GenericRepository: saving duplicated CRUD code for any CustomerRepostiory/ UserRepository that inherit it.
Every infrastructure has its own set of trade-offs. By presenting only one perspective, you are providing a one-sided view that may not capture the full complexity of the situation. Generalizing based on this limited perspective, such as applying it universally to all cases like a generic repository, overlooks the nuanced considerations and potential variations inherent in different scenarios.
I have other videos covering different takes on the repository pattern
Don't Repeat Yourself, so Generic Repository gives you that and only that and your GetQueryable() should be protected not public...
Fair enough
Yah when our team talks iRepo pattern we include the IUnitOfWork pattern in our meaning… will be nice when copilot just generates all the boilerplate code for us… but do feel it gives us good value for tests when needed. And in theory we could switch out our database layer MSSql/Oracle per customer preference
What's the value of unit tests for the DB though?
@@MilanJovanovicTech true, we have a couple… but they would be better written as integration tests to be honest
But didn't you use a generic repository in your last paid course? 🤔
Not how I'm describing it here - check my more recent video about this.
Generic Repository + Specification Pattern =
That's even more of a mess 😅
Then what you recommend 😢 if we dont use generic repository pattern.. then which patter i should look for.. please tell me.. 😢 i am junior software developer.. i need your quick suggestions please.
- EF Core
- Specific repository
@@MilanJovanovicTech thanks ❤
"why not Just use ef Core instead..." .. First: Because not all data comes out of a SQL database, Second: Also Not everyone wants to marry Microsoft products... did you read Clean architecture, or Just talk about IT ;-)? I totally agree with the Point that a generic Repository is no good Idea if Things grow fast. But Sometimes simple CRUD is totally fine when things should be easy and fit in a unified model ("the next scary anti pattern"😂).... Here is my opinion: dont overengineer eveything with ddd paired with clean and keep your scope, Sometimes this is enough! Also thank you for your ideas to this topic❤. Seldomly younger developers care about Software architecture!
If you advice is don't overengineer, then why not use the simplest tool for the job?
@@MilanJovanovicTech Good point, but the tool we are talking about is not simple (EF core). As a driver of a car you dont need to understand whats inside the engine. But as a mechanic you have to solve problems that have to do with engines (or replace the whole damin thing :D). If you install an engine that you dont understand, you could get problems you dont understand. To use EF core is easy at first glance, but hard to master in many ways. What i was pointing at with overengineering was the fact that you say "use EF core instead of a (generic) repository because its easier". But then you (as a developer) depend on another external tool thats maybe not necessary because its more complex than just to have a raw and plain repository that writes SQL against a relational DB. I also like to use EF Core + LINQ because it totally fits into modern language of C# (with declarative approach). But its not easier! It requires knowledge about LINQ, you need to read Logs to see if the SQL performs bad, you need to have a clear Model (not a domain model, but a data model that reflects your db table), you need to know about lazy loading and eager loading, and so on.
@@sotsch9280 "If you install an engine that you dont understand, you could get problems you dont understand." - the same applies for Database engines 😁 No ORM will save you from having to know SQL and how to use a database.