This Will Make Your Repositories Obsolete

Поділитися
Вставка
  • Опубліковано 31 тра 2024
  • Using repositories in a setup with Entity Framework Core is a no-go from my point of view. The main reason I think this is because the DbContext class already encapsulates repositories (the DbSets) and a unit of work (SaveChanges). On the other hand, if not using repositories, service methods or handlers (if you are using MediatR) tend to then get cluttered with data retrieval logic. So, how to solve that? Well in this video I will show you a technique that keeps your classes free from data retrieval logic and renders the use of repositories obsolete.
    #dotnet #efcore #csharp #aspnetcore #repository
    Join this channel to get source code access and other perks:
    / @codewrinkles
    Content
    1. Intro: 00:00
    2. Overview with repositories: 00:42
    3. Setup without repositories: 02:02
    4. A Common objection: 03:06
    5. New technique to solve the objection: 03:44
    Also follow me here (especially if you are a self taught developer):
    ✅My other channel: / @danpatrascutech
    ✅Facebook: / danpatrascutech
    ✅Instagram: / danpatrascutech
    ✅TikTok: / danpatrascutech
  • Наука та технологія

КОМЕНТАРІ • 87

  • @empireofhearts
    @empireofhearts 9 місяців тому +15

    i have a project using this approach makes it hard to write unit tests using mocks on Dbsets or datacontext. Also, the extension methods becomes kinda pseudo repositories if we start stuffing methods in there and they start showing anywhere you use context as they are extension methods on context itself, if you are not careful. if you okay with using any InmemoryDB implementation and limitations that comes with the setup then this works.

    • @Eirenarch
      @Eirenarch 6 місяців тому

      mocking DbSets and DataContext is not the right approach anyway. Spin a database (SQLite or the real thing) and test your logic together with your queries

    • @vitalyglinka466
      @vitalyglinka466 5 місяців тому

      @@Eirenarch why should he spin up a database if he wrote a unit test? Generally, unit tests are not supposed to be run in the paradigm of "spinning up s SQLite or whatever db"

    • @Eirenarch
      @Eirenarch 5 місяців тому

      @@vitalyglinka466 because these types of tests (semi-integration tests) are better than unit tests. They test more things, they test the queries. What is more the queries are in most cases part of the business logic. A WHERE clause is in fact business logic and should be treated as such and paired with the rest of the business logic.
      So you get simpler code and test more things

    • @vitalyglinka466
      @vitalyglinka466 5 місяців тому

      @@Eirenarch the guy wrote about UNIT tests. Tests that're supposed to be simple, very quick and test that a SUT (system under tests) just calls all necessary services once, or twice or whatever with a specific set of parameters. That's why mocking is necessary. You can't do such a simple thing by not having an abstraction over a db context. What is a semi-integration test? Let's not invent additional types of tests in favour of accepting a bad designed system that doesn't support to be tested by just a plain simple unit test.

    • @Eirenarch
      @Eirenarch 5 місяців тому

      @@vitalyglinka466 yes, that's what he wrote and I am telling him that this is suboptimal approach. That's not "simple", that's far more complicated and less useful in practice. No abstractions, no mocking.
      The best way to test is spinning up a database so that EF can generate actual SQL with database semantics, you get to test includes and so on. I called it semi-integration because it doesn't test the controllers which would be an actual integration test. I don't care about the name.

  • @rekardev1
    @rekardev1 9 місяців тому +4

    I use repositories to abstract my data access layer. In case in future I decided to use Dapper I don't need clean my services from those Db Context. Great content. Thank you.

  • @ratheesh105
    @ratheesh105 9 місяців тому +6

    Yes need clean architecture content please

  • @rr.vasconcelos
    @rr.vasconcelos 9 місяців тому +3

    I didn't have that perspective, I found it amazing. I always make these abstractions of EF in my projects. However, I was left with two doubts:
    1 - What if, for performance reasons, I decide to replace EF with Dapper in a query?
    2 - Why is unit testing repositories considered wrong?

    • @Eirenarch
      @Eirenarch 6 місяців тому

      Let me guess! You've never actually had to replace EF with Dapper and live with the wrong impression that the repository will somehow help you with that?

  • @TonoNamnum
    @TonoNamnum 9 місяців тому +2

    You can make all your entitie modes inherit from IMyEntity for example and inside that interface you can have the property Id. Then on the generic method you can specify where T is IMyEntity and it will be eassier in my opinion. You will also have intelisense.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому +3

      Yep, that's a good approach I think. You can have also AuditableEntity to contain creation, update dates and so on and then use that for different filters you might need. I just wanted to showcase an idea. It's now up to everyone's creativity to enhance it :)

  • @bogdanb904
    @bogdanb904 9 місяців тому +12

    In my opinion, using repositories is more about setting limitations, since the DbContext allows you to do everything. But adding a repository layer, you only expose the operations that are considered to be allowed on a given entity.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому +4

      Setting limitations from who? In the end it's still you and all the devs on the project that can do "everything". It's just the question if you do it in one class or the other.

    • @bogdanb904
      @bogdanb904 9 місяців тому +3

      @@Codewrinkles Considering the scenario in which multiple teams work on a project, and the data layer is provided as a NuGet for example. Or safe-guarding from introducing un-desirable side-effects. Maybe on the add method, some obsolete fields must be update in the db for the sake of integrity (even though a trigger could be used, but that's a different story :D) until they are completely removed, and that should be abstracted away from the use case. Either way, repo or no repo, is more of a flavour than a deal breaker.

    • @Veretax
      @Veretax 9 місяців тому +6

      ​@@Codewrinkles​Yes from whome, the answer is often, the boogey man ie some unknown potentially zero day security exploit. However, you basically just made your extension methods the repository though? I'm not sure what this really changes, its just a different way to call things.

    • @ivandrofly
      @ivandrofly 9 місяців тому

      ahaha, I like "From who?" You know sometimes we do unnecessary things in programming @@Codewrinkles

    • @Stettafire
      @Stettafire 9 місяців тому

      Personally I found EF to be a limitation in of itself, but theres that. For basic activities it's fine

  • @nove1398
    @nove1398 9 місяців тому +1

    This is a pretty neat implementation

  • @ja_mcito
    @ja_mcito 9 місяців тому +2

    It is possible that repositories are useful for a separate implementation of database caches with mappers.

  • @robsonfaxas6574
    @robsonfaxas6574 9 місяців тому +2

    I understand the point, but I wouldn't use generics or extended methods for this situation. However, if we have a complex business logic applied to a query and shareable between different repositories, I would like to encapsulate it in extensions and possibly, but not always, using generics. My problem with generics in this situation would be the fact that any table would have the option to call by Id, even the tables with composite keys, without a single "int Id". This method would be listed but not effective, driving to a false usage.
    But let's suppose I have to check for a pattern, such as the confirmation of the security digits in a credit card, and maybe we have 10 different types of classes for cards with this same logic (infinit, black, gold, platinum) each one with a different T class (probably using a condition "where T : ICard" or something), so in this situation, a logic inheritance to a query (probably returning IQueryable to add to another query if needed) would work with an extension method with generics in a repository.

  • @jeffafaaah
    @jeffafaaah 9 місяців тому

    Very well explained! We have a big love for extensions, it keeps everything so clean. We always use a abstraction for domain models repos. the interface lives in the domain layer. The domain determines which functionality is possible on the repo trough the interface. Specification Patern also might be interesting.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      For me, it's conceptually wrong that the domain needs to know about how data will be persisted, so that it defines interfaces. This is totally contrary to DDD principles and I stay away from this.

  • @danielvanderstelt
    @danielvanderstelt 9 місяців тому +2

    Interesting take on no repositories. I stopped using them a few years ago and have not looked back. Most times it just provided a findx over a find in an orm. And essentially the dbsets are your repositories.
    EF provides a pretty evolved unit testing and mocking implementation now.
    Get your service layers in order and it flies fine.
    But it is all a matter of opinion I guess.
    Yes to the clean architecture thing and thanks again!

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      Thanks for your comment. I'm also not looking back at repositories :)

    • @empireofhearts
      @empireofhearts 9 місяців тому

      What unit testing strategy you follow? You cannot mock dbset in EF core

    • @danielvanderstelt
      @danielvanderstelt 9 місяців тому

      @empireofhearts Yes I was a bit to bold on it having its own implementation. We have a few older projects on older ef where I mocked it like that. Used moq for entitycore for mocking on ef core. And now looking to rid that with these extension methods.
      I understand repositories in CO.plex systems can have a place but it often times just abstracts over an abstract of an abstract.
      Actually I honestly try my best to keep data out of the unit tests since it should not be dependent on it, try but yeah mixes sometimes.

    • @empireofhearts
      @empireofhearts 9 місяців тому +1

      But you cannot mock static methods unless you use special mock libraries and the resulting test code is generally not pretty ☺. At some point where you have to add data to entity or save to dB will be part of domain and if you are not mocking or using In memory dB implementtion it would result in integration test right? In the end what's the testing strategy you follow for your EF layer other than trying to keep dta out of tests

    • @Codewrinkles
      @Codewrinkles  9 місяців тому +1

      @@danielvanderstelt The main part here is that you don't unit test that. You integration test it using "the real deal". Usually I would have request handlers and rich domain model. You unit test your domain and integration test the handlers. Mocking everywhere is by my book a sign of bad application design.

  • @fpiras89
    @fpiras89 7 місяців тому

    Just subscribed to the channel as there are amazing contents!
    I like this approach which allows to remove the repository layer and at the same time encapsulates data retrieval logic. However, I would like to know how this can be used with the clean architecture without breaking the dependency rules i.e. preventing the application layer to depend on the persistence/infrastructure layer.

  • @z0nx
    @z0nx 9 місяців тому +1

    This is just moving code somewhere else, applying reuse just the same. I still believe that abstracting out the object retrieval is beneficial in the application/usecase/domainlogic/whateveryoucallit whenever you need to mutate something in the database. Especially if there are any rules and checks that the data requires to be consisten. If that is by using an interface or just plain old Funcs, it doesn't matter, as long as it is free of implementation details.
    Specifically for GET/readmodel endpoints, I agree with the message that @CodeOpinion puts out: most of the time you don't need any abstractions, and calling the query directly is the most simple and effective, no need for repository or interfaces of any kind. But do still rely on e2e tests/api tests to verify things are being returned like it should.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      It's not just "moving code". If you have repos, you create coupling. Using this approach doesn't. Coupling is what adds complexity to application.

    • @z0nx
      @z0nx 9 місяців тому +1

      @@Codewrinkles Isn't it the opposite? Like you said in the video, most of the time repos are unneeded abstractions, decoupling the service from EF/persistence. Without repo interfaces, you couple the service to EF. In the end the difference is in using interfaces or not.
      My point about moving code was in reference to your solution to the "objection". Moving the clutter from services to extension methods is literally just moving and allowing reuse of code. Besides that, this is usually not the objection people have to not using the repo pattern, but yeah..

  • @DmitryV_HF
    @DmitryV_HF 9 місяців тому +7

    My opinition - very bad example, and no answer to video title question.
    One GetByIdT method - this code made in abstract Repository class, same like maded by your.
    You tell "EF already encapsulates repositories", but moved this to extensions class. If obsolete, then everywhere.
    Next, if you want add some logic (on big entherprise project), so you will need... to create new methods for concrete class. And soon, you extension class will be bigger.
    So, i dont saw objection and response. Sorry ;)

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      "One GetByIdT method - this code made in abstract Repository class, same like maded by your" I guess that sums up why you don't need a repository at all :)
      On the other hand, when you don't use repositories one of the major challenges is to handle the data retrieval logic in servce methods or handlers. In this video I have provided a possible way to keep those clean. therefore, the argument that a repository helps you to keep your code cleaner doesn't stand anymore.

    • @DmitryV_HF
      @DmitryV_HF 9 місяців тому +2

      ​@@Codewrinkles , so services must be obsolete too. Your helper doing same what service. Someone must have single responsibility for reading db data (apply specification, use mapping and etc.). Before - this made repository. Now you move db reading to helper class.
      Or your example badly, or it didn't convince me again. :)

  • @nitrovent
    @nitrovent 9 місяців тому +1

    I like your approach and reasoning regarding unit tests (in your reply on a comment). How would you in this case implement e.g. a duplicate check?
    Say checking if a user with the same email already exists. As I possibly don't want any depencies in my domain objects/aggregates, this check would have to occur at handler/service level.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      This is a good candidate for an integration test in my opinion. This logic exclusively relies on the database and what's in it. If you test it, you want to test the real thing, not a mock.

    • @nitrovent
      @nitrovent 9 місяців тому +2

      @@Codewrinkles Hm, take any other scenario where it is a business requirement that I cannot create duplicates of something and I want to implement and test that - regardless of any underlying database. I know people debate whether my entity could get injected a service or repo/dbcontext it can call itself to check but I don't want any dependencies with relevant behaviour in my entity/aggregate/domain object. Normally I would place that check in a (domain) service that calls the repo for that email/id/whatever to decide if the creation is allowed and to only create and save the entity if there's no duplicate. If I have that check in my reposity, I could mock that. As an extension method, not. Though it is something I implemented and have full control over.

  • @Eirenarch
    @Eirenarch 6 місяців тому

    I tried this as it seemed a good idea and didn't like it. Ultimately I came to the conclusion that the query is part of the business logic, is better kept in the service code, and is rarely reused between the different services. These .Includes are more often than not specific to one method or a couple of methods in the same service class. Just embrace queries in your service layer and you will live happier life

    • @Codewrinkles
      @Codewrinkles  6 місяців тому

      Thank you very much for sharing your experiences on this topic.

  • @mihaiga
    @mihaiga 9 місяців тому +1

    I would still use repositories if I need to isolate the unit if work. It's a mess when each service has access to SaveChanges

  • @richardaubin1951
    @richardaubin1951 7 місяців тому

    Interested in your take on clean architecture.

  • @c28ccd0e
    @c28ccd0e 9 місяців тому

    That's very good to know THANKS

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      Always welcome! Thanks for watching

  • @matejl92
    @matejl92 9 місяців тому +1

    Arent those extensions just repositories, written in a different way?

  • @denisthedev
    @denisthedev 9 місяців тому +1

    It's an interesting approach, but I do not see much of a difference or even advantage in comparison to repository:
    1. I guess this makes unit testing more difficult.
    2. What if I want to switch from EF to something else (I know, this does not happen a lot probably, but it's still an option)
    3. I like to use repositories to outline the specific methods that are allowed to use from the "persistence layer". With exposed context, you can do basically anything you want (you can do that with repository too, but it forces you think about what you do, you have to name the method, etc)
    I would probably apply "don't fix it if it ain't broken" rule here.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      1. It doesn't. Unless by unit testing you mean mocking the repository. Which is in my opinion a bad thing to do. Reasons are in another comment.
      2. For me, this is not an argument. In 10 years of working mostly on enterprise apps, this was never in question. Not even once.
      3. I think you can still do whatever you want to do. The only question is if you do it in repos or directly using the DbContext. That's in my opinion one of the major reasons why adding a new layer over something that's already an abstraction doesn't really bring any value.

  • @arunbm123
    @arunbm123 9 місяців тому

    Brilliant

  • @FilipBeunens
    @FilipBeunens 9 місяців тому

    Awsome post!

  • @morph442
    @morph442 9 місяців тому

    We use the no-repository-approach since years and it works great. An repository with EF is just additional, irrelevant overhead, overthinking and over-architecture.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      Glad you think about it this way. As you probably observed, there's also a lot of disagreement in comments.

    • @morph442
      @morph442 9 місяців тому +1

      @@Codewrinkles That's okay I guess. Some like hamburgers, some like cheeseburgers. At the end it's all calories and fat ;)

  • @user-uo7ch2lf3z
    @user-uo7ch2lf3z 9 місяців тому +2

    This is good suggestion!
    I may use this right away.
    And YES, would love to learn from your experiences and tips on Clean Architecture.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому +1

      Great you found the suggestion useful.

  • @jtesh
    @jtesh 9 місяців тому

    unit testable? you didn't cover that

  • @Adiu72
    @Adiu72 9 місяців тому +2

    But with repositories you can easily write unit tests by mocking those repositories. With extension methods it is not the case. I do not see the use case for this change. I would still go for pure EF or repositories instead of those static methods. More disadvantages to me than advantages.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      I think that is the totally wrong way to use mocks.

    • @Adiu72
      @Adiu72 9 місяців тому +1

      @@Codewrinklesok, but why?

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      In my opinion (following other more smarter people than me) mocking is something you need in case you have systems that you don't control. However, even in that case, unit tests should not rely on 3rd party outputs. One very common way to make mocking obsolete is to move your logic in the domain classes. In that case you can easily unit test that. And if you do it, in your service methods or handlers there isn't anything left that needs unit testing. In order to see everything performs correctly with "the real thing" you have integration tests. Having mocks in unit test is for me, and for the code I write, a sign of a badly designed class/system/module and I refactor it. Obviously, I don't want to impose it as a "best practice" for everyone. It's just something that I've learned for myself on the projects I worked till now.

    • @user-bx2er2zx5u
      @user-bx2er2zx5u 9 місяців тому +1

      @@Codewrinklesmake video , where you show this approach!

    • @Adiu72
      @Adiu72 9 місяців тому

      @@CodewrinklesOk I got your point. In case of a nice project with business logic classes which take arguments and produce responses which is then saved to DB outside of the class it can be a good approach (still I do not see a lot of pros, this is a new class with the same methods which can be in the repository but you do not need to use DI thanks to that). Maybe I am unlucky but in most projects I do not see such approach (so we have handlers with business logic which use repository/ef directly) and having repositories allows to write unit tests without rebuilding the whole legacy code. But you are right - this is rather a patch then the right approach. Thanks!

  • @ramanam123
    @ramanam123 9 місяців тому

    I think this approach will make unit testing difficult because we cannot mock out repository

    • @Codewrinkles
      @Codewrinkles  9 місяців тому

      Mocking repositories for unit testing is something that's a red flag for me, no matter if you use a repository or not. It's a signal of bad application design.

  • @quranthecompanion4528
    @quranthecompanion4528 9 місяців тому

    Its called specification design pattern.

    • @Codewrinkles
      @Codewrinkles  9 місяців тому +1

      Can you elaborate on this? How is this the specification pattern?

  • @torrvic1156
    @torrvic1156 8 місяців тому

    Sorry but I didn’t got it. I saw in your other videos you promoted repository pattern and now you saying that we should not use it. Pretty vague.

  • @shinkathe
    @shinkathe 7 місяців тому +1

    So you made your repository into extension methods - that's hardly the same as having no repositorylikes🤔

  • @Moschma19
    @Moschma19 4 місяці тому

    @Codewrinkles it would be awesome if you could help me thinking that out.
    So about base services or base handlers is that a thing to?
    I was thinking about an base services using IServiceProvider but i had to inject IServiceProvider for each implementation.
    ```
    public abstract class BaseService where T : BaseService
    {
    protected readonly ILogger Logger;
    protected readonly IServiceProvider ServiceProvider;
    protected BaseService(IServiceProvider serviceProvider)
    {
    ServiceProvider = serviceProvider;
    Logger = serviceProvider.GetRequiredService();
    }
    }
    ```
    and an implementation would always have to inject the IService Provider
    ```public ExampleImplementation(IServiceProvider serviceProvider) : base(serviceProvider)```

  • @hanneskasel1853
    @hanneskasel1853 6 місяців тому

    dont use EnsureCreated but Migrate

  • @ratheesh105
    @ratheesh105 9 місяців тому +2

    First view 😊

  • @IanMoore4UD
    @IanMoore4UD 9 місяців тому +1

    Love the idea of no repositories and will be using it in some new projects, I would love to see your video on clean architecture and how you implement it

  • @user-dc9zo7ek5j
    @user-dc9zo7ek5j 9 місяців тому

    I watched a view on some person that demonstated how he did "clean" architecture, and the only thing he did was to create a class which has 1 method that calls .SaveChanges. I do not understand why people are creating repository pattern only to call EF, because EF itself is an abstranction of the interaction with the data source provider, not with the database directly.