The DB Context interface is basically an IUnitOfWork, whereas the DbSets act as repositories. I think this is why there is a lot of debate on not using Repositories with EF.
I think what Milan showed was a way to sepparate the repository aspect from the IoW aspect by defining interfaces that act as facades over EF. I this is possible to have two interfaces, one that only defines the DbSets and another that only implements SaveChangesAsync that can be used only in use-case implementations.
@@mihaiga I totally agree with you, because the dbset is tied to ef, therefore another interface will be required to house properties for other orms or nosqls. Also, an interface particularly for savechanges is required since it is tied to ef (interface segregation principle in SOLID).
@@ibiballer2003 right another interface for another implementation of orm. this doesn't make sense to me to design the app this way.. I look at the application layer as a module with a bunch of sockets like a power strip. the interface contract creates a unique socket formation and the implementations are modules you can plug into them. following that logic why would you design your application to swap out the plug. instead you could design your app to be more universal and instead plug many things into that socket without needing to change the socket or under the hood wiring / circuitry.. Just my opinion.
But it's not great. Your contract is now the full IApplicationDbContext that you need to verify and check in your tests. Really breaks the Interface Segregation Principle.
@@MilanJovanovicTech repositories guide others on how to work with a given entity. Some examples: 1. When you use an aggregate pattern you should access an entity only through the aggregate root. The repository pattern helps you to enforce it 2. Repository can tell you whether an entity can be deleted or it abstracts a way to delete it (it's helpful with soft deletes) 3. There are domain problems where entities can be create-only and should never be updated 4. Repository encapsulates re-creating objects correctly from the database (helpful with eager loading related entities using.Include() etc) Of course, each abstraction adds complexity so using repositories, aggregates etc. should be justified. Personally, I use both approaches, even in the same application. Different modules have different complexity and needs
100% agree with Piotr. In DDD the repository pattern has it's place. In big projects having small agregates and eager load the entire graphs is a good idea, forces you think about where should be the boundaries between them instead of everything reference everything, lazy loading pulls 30% of the database and devs complain about the ORM being slow.
Tbh in many cases repos and uows hide many underlying operations so people start using repo operations “because they are there” but under the hood they can easily execute a lot more operations than they need. In many cases I’d actually prefer to have the access to dbcontext and also see exactly what’s being executed.
The repository pattern is a really misused and misunderstood pattern. If you’re applying DDD, they are vital when working with aggregate roots. To understand the repository pattern, you need to understand the role of aggregate roots in DDD. If you don’t do DDD, then I totally agree, you don’t need repositories, but if you apply DDD, then this is a totally different question and not applicable to what you’re trying too demonstrate here. The major reason for this confusion is that the vast majority of the examples you see on the web of repository implementations, are not applied on aggregate roots that adheres to the rules of DDD.
This is my favorite approach, with a few slight changes. In the interface I define for example: public dbSet orders {get;} (only get) in the implementation the Set is assigned. Also add public DatabaseFacade Database { get; } for transactions.
Get can be also implemented as { get => Set(); }. With this approach you don't need setters at all and this also doesn't generate null reference warnings.
I remember you asking me why you even would do EF Core directly. It depends on the use case. But unless you really need to switch out EF Core sometime or even creating mocks this would be totally acceptable. But if you are doing DDD, you should consider creating repositories for your aggregates - to get a standardized interface that is mockable - and use the DbContext directly (or via an interface) for just accessing data in a flexible way outside of aggregates.
An important drawback is that the application project is coupled with EF and using a different ORM without rewriting the project is not an option anymore. In most scenarios it can be a valid approach anyway.
@@LeeDale1981 I agree.. What is the purpose of the abstraction with reference to DbSet to begin with?.. couldn't you just inject the context directly? isnt the abstraction with reference to DbSet just a leaky abstraction?
I think this approach is very pragmatic. Sometimes you create abstractions by using repositories and at the end of the day, if you switch to a different data store (i.e. a document database), you end up having to change your application layer to some degree. By using this approach you get speed by introducing some coupling (to EF), which is an abstraction already so it may not be a problem for many applications.
When you directly use the DbContext in your application layer, a major issues I see is in your unit tests as you face several challenges related to mocking of the dbcontext, the only real option is an In-Memory Database. Where you now have more of a integration test than a unit test.
@@MilanJovanovicTech When you use an in-memory database, you are testing the interaction between your code and the database, albeit a simplified one. This introduces a dependency on database behavior, which is typically beyond the scope of unit testing. You are bluring the lines between unit tests and integration test. Also some versions of EF mocking the dbcontext is a massive pain.
@@thealbear3629 This I would consider integration testing: ruclips.net/video/tj5ZCtvgXKY/видео.html Since it's using an actual database in a Docker container
Hello. I'm trying to create an architecture. But the repository doesn't make much sense to me. And basically against SOLID. What's the harm in using this approach on large projects? And do you think there is flexibility for variations? And is there any benefit to using mediatr and cqrs without using separate databases for read and write?
I like CQRS for the logical separation, more so than the physical separation at the database. It's a personal preference however. As for using this in a large project - you'd need to solve one problem: query reuse. Then it's fine.
Honestly, I do both in my application layer. I inject a class that holds all my repositories, so that I can easily use the specification pattern, since my repositories can query by specification. In cases where I need some rapid development and get things done, that class also holds a property that gives me my DbContext directly and I can use EF Core as I normally would. After the test phase, I push the code to the repository and revert back to a 'clean architecture' code.
This was a problem with the initial Jason Taylor Clean architecture example. He also decided that the dependence on ef core was something he could live with.. I've since improved upon that initial source and have been able to abstract that away using IDatabase and IRepository abstractions.
@@MilanJovanovicTech No you create your own IDatabase abstraction that has many IRepository sets has no dependence on EF Core. your application layer should have no reference to the ef core library.
I wasn't clear by using the name IDatabase since ef core has an IDatabase abstraction defined. I was saying that you create your own base IDatabase abstraction to inherit from. This abstraction would have unit of work methods such as save changes and begin transaction etc.. then you can create extensions of that abstraction like IMyApplicationDatabase : IDatabase and that abstraction has the repositories that your database actually has. so instead of referencing ef core DbSet you instead reference IRepository. Then in your infrastructure layer "Persistence Layer" you have many implementations of IRepository such as maybe EFCoreRepository or DapperRepository etc.. depending on which technology you want to use for interacting with your database.
@@MilanJovanovicTech no not really.. the unit of work abstraction should have methods pertaining to the persistence. it isn't conforming to any implementation it just provides the interface for persisting changes to your database. This means also that in your application layer you can't rely on ef core change tracking.
One more good approach for discuss. Thanks! But i still don`t understand why people talk about wasting time for implementation repositories, just use existing implementation like Ardalis.Specification or create own implementation for future. If dont like Repo- use this approach.
IDbSet represents a collection of Entities just like the repository pattern Entails. However, it's an Interface specific to Entity Framework. Using this Interface directly isn't a very clean practice as it leaks the IDbSet obstruction from Entity Framework and into our application layer. In addition, exposing all of the repositories and the save method in the single IDatabaseService interface potentially violates the interface segregation principle.
The only one alternative to EF is Dapper, we use dapper when need performance. Dapper makes a difference but only with long stored procedure which actually cover more than one functionality. So i think this change would be rely on replacing many functions in C# to sql procedures and repository would not be needed still.
Hi, Milan. I have another question. I try to follow DDD, which involves having entity methods like User.ChangeStatus(…), User.Restrict(…). The problem I encountered is that I have no idea on how to properly map my REST CRUD interface to that. Also, in CRUD-like interface I’d like to make use of JsonPatch, but it breaks invariants by requiring public setters. After applying Patch to my Entity I have to run a Entity-wide Validator, which is rather a CRUD option, not DDD one. I consider using Task Based UI, what do you think?
I have noticed Ardalis had the same situation in his DDD eShop project. His solution was to use PUT, have general purpose APP Service Update(…) method which selects every PUTModel property and maps it to Entity property by calling Entity Domain Methods for each. Like; user.ChangeUsername(); // even if it was not changed in PUTModel user.ChangeAddress() …
i've got a question: If you've got a lot of simple queries like "GetOrder" in this case, which doesn't have any use case type logic- just data retrieval. Is it really bad to have dbContext/unit of work available in the presentation layer? I have got ViewModels which take in take in a domain entity in a constructor and map it.
@@MilanJovanovicTech How so? I think EF core team recommends using public DbSet Customers => Set(); over public DbSet Customers { get; set; } Now anyway. So the first form would slightly change to: public IDbSet Customers => Set();
Thanks for your toturials ❤, Could you please give me a source(c# implemenation,...) about Generic repository interface that capable to switch from sql DB to document DB?
I dont know if you have handled it elsewhere, but our domain objects are not eimilar to thr database wnd 2e can't simply change. Read one item has different tables. And those tables are also used for other models. How would you deal eith such as thing? Charging the database is not really an option
This approach is fast and pragmatic for sure. I think this works really well on smaller projects or in a small team. One thing I kinda miss is code reusablity (maybe you or somebody else could give me a hint here ;-)). When the logic gets more complicated, the code starts to get more and more smelly. Especially when working within a team with different experience levels. Some team memvers start creating some sort of services to reuse code... others extensions... others just implement everything within the handler. So my biggest issue right now is probably maintainability. That's when I would prefer to use an additional layer (call it repository-, adapter- or whatever layer) so everyone just knows where to "place the code". It's really funny because I (and my team members) started to implement this approach while also encountering the issues I've mentioned :D any help or ideas would be really appreciated
My thinking was either: 1. Extension methods to encapsulate queries 2. Static query clasess 3. Repository/service Any one of these will work just fine.
Unless you already know the whole architecture (which is rarely the case), I believe that procedural (in the handler) programming is the best because it's gives you the most fluid code. The tradeoff is conciseness but that's OK in my opinion because clarity suffers not so much. However, if you don't refactor that procedural code into proper classes, then you will end up in a bigger mess. So it takes expertise to guide the project
@@MilanJovanovicTech then it becomes an integration test, not a unit. Moreover, you have to care about real DB in your CI pipelines which is not convenient.
Hello, Milan. I've been following your videos. They are excellent content. Thank you for sharing knowledge. In my opinion, this is not a very cool approach when it comes to writing (commands). I prefer to go through the repositories and unit of work. However, when it comes to reading (queries), I find it quite interesting. I would use it in the QueryHandlers to return QueryResult - Response objects using EF Core projections. It would bring excellent performance gains, and we wouldn't need to use another DTOs with Mappers, returning the projection directly to the QueryResult. (avoiding unnecessary database overhead).
I used to use this approach frequently in old EF (before Core) as it was very unlikely we'd be changing ORM but now with Dapper providing better performance I like to keep my options open. I don't think there's anything wrong with this approach though if you're sure you want to stick with EF.
Hi. I think about learning C# with .NET and I use your videos to explore. Also it helped me a bit with the DDD and CA concepts. I have a question. I often see you making methods asynchronous, but then you await for the results anyways. What's the reason?
Could you make a video about multitenancy using a single database? Or a series of videos on this matter. Would be interesting to see how you'd implement it :)
Multitenancy using a single DB throws a lot of issues including but not limited to security, data corruption, performance, individual tenant backup etc. etc. etc. I strongly recommend using separate DB per tenant, even if you think you have it under control with your code. Just saves a lot of future headaches.
What really buggers me is the ProjectExplorer of Visual Studio, not being able to create a Folder in the Directory on my Machine by Default , instead just referencing one. So in the csproj it looks well sorted, then u look via win explorer and have nightmare of a structure, especially when renaming folders or Projects. Hotkey F2, i would guess will do the same as context menu> click-> rename, but lol it doesn't. So also the namespaces easily get twisted.... Sry. just wanted to spout that. Even if wrong place. :D
Repositories at the end of the day are a design pattern. It is the developer that decides if they want to implement it or not. If you want to have a feature map structure aligned with the feature that's been developed, a repository pattern would be in violation of the basic principles. So it would make sense to use commands instead. This all said tho, a feature map structure on the domain level has a tradeoff, especially in the architecture where entity framework would be dependent in all layers. I see too much tech dept to implement it that way.
Is this part of a series? The eShop? Thanks for sharing! I normally don't use EF Core (We use a developed in-house micro-ORM) but after seeing this, it looks nice clean and easy, will have to start a test project to try it out some more.
Assuming you have more than one DB used (let's say SQL and Mongo) - a repository pattern will still be better fit. Also assuming you have an existing application where you choose to move away from EF or change DB or incorporate other methods of connecting to the DB (for performance as an example) - having all this in a repository will make your life much easier.
I just thought of this now too.. if you are going to reference ef core from your application layer then why not just inject the ApplicationDbContext class directly? I'm not sure what value the IApplicationDbContext adds or what is being abstracted away. It just seems like a leaky abstraction at this point. By leaky abstraction I mean it exposes elements of the implementation that should be abstracted away.. cough cough.. DbSet type.
DB Context is a UoW/Repository pattern implementations at once. That reminds me of NESTJS (speaking of the NodeJS world) where you use directly a repository involved with its default ORM (typeorm) and it's almost the same as how you used EF. Interesting topic :)
I think the main reason to create repository abstraction is to alow the change ORM without impacts or code review. Moreless, repository is a domain pattern. So, why not?
I know I'm late to the party, but I just watched this video, and it's still useful ;). While abstracting `DbContext` is debatable subject. I generally like to either stick with `DbContext` and implement service classes out of it, or implement the interfaces and then hookup the Dbcontext on separate layer. The later approach separates the data provider, which means easy to change the data provider, or have multiple providers. If there is any reason to use repository with EF, then what I would do is move EF to a separate project, and keep its context along with properties internal, and only expose the repositories. this way, the consumer will be forced to only use the repositories, and don't have access to the underlying context (can bypassed using Reflection tho 🤪 ). Great video as always I really like watching your videos, don't you ever stop 😎👍
@@MilanJovanovicTech you've mentioned that in some of your videos (I'm a good watcher ;)).. To be honest, I've never worked in a project uses that pattern. I think it would enforce the security isolation; but I can't think of a use case to support that thought! Maybe my brain needs a new software update 😣.
Amazing video as always, can you please create a full course about DDD from start to finish? maybe even not in RUclips but in Udemy. It would be something I'm sure everyone that takes application architecture seriously would like to invest in.
Not keen. Having to change the Application Layer frequently undermines a key benefit of Clean. EF core will likely need frequent updates to dependencies. Plus it undermines training of trainees or newcomer junior devs who would see the dependencies and think they can start adding more and think they were trained wrongly to keep dependencies out of inner layer.
Hi Milan, thanks for all great work I am aspiring junior .net dev and I learn a lot from you. My question is: this approach is only possible when commands and queries are in the application layer. However, I have heard opinions that they belong to Core/Domain layer. What do you think? Because otherwise, it's not really possible as the core layer doesn't have any reference to infrastructure layer. Because of that, we cannot use infrastructure types there.
Easy replacement of SQL with NoSQL is not always possible. If you replace relational DB with a document-oriented one, you will probably have to re-write repositories and logic, as the document structure will differ from the relational one.
I don't agree much with this approach as you are adding a direct reference to entity frameworks in the application project since while using an interface, within it there are DbSet. I prefer the abstract repository approach to decouple the application layer from the infrastructure layer. What do you think?
I have to say that I'm not a fan of using EF Core. To me, unless you implement it within the repository pattern, you are always tied to using it as a provider. I also don't like the migration strategy of scaffolding via a command line tool, I like to code my own migrations whether in SQL or using a tool such as FluentMigrator. I quite like using Linq2DB within my repositories as I can automate the mapping based on the FluentMigrator table setup. For the most part, I find myself dealing with simple CRUD operations so that approach works fine. Sometimes there may be some more complex queries that needs to be faster, for example running a complex report, and for these I might add a separate interface and deal with them in a different way - e.g. executing a stored procedure or custom SQL.
Clean or not that is just opionions as you said. It is fast in the beginning, but scale really bad a year in a project. I am using repositories becuase I know where I get my data, I don't care if it is EF or dapper or if I need to change that to an api or another database in the future or just update the query I know where to look. To many projects that do not use repository implementation have the database code spread out everywhere with dublicated code.
to be honest, with repositories you just reimplement LINQ for EF. That's it, it's a waste of time. On top of that, what does you repository return, IList? If so, sooner or later you will end up with code that pulls multiple records to get a single one in the end. If you return IQUeryable, what's the point of repository? Unless you do it just for unit testing, it's pointless
The only use case(s) for the repository pattern that I see is when you want to mix up Dapper / Norm and Entity Framework Core (as in, when there are a few cases where you have to write your own raw queries that won't be mapped to a DbSet). For anything other than that, I believe one should stick with NOT implementing the repository pattern, but that's my 2 cents only.
The key concept in clean architecture is that dependencies only point inwards. Since EF is for persistence, it is part of the infrastructure layer. In this example, EF dependency is brought into the application layer, which breaks the first rule of clean architecture. If initial development speed is a priority, why not add EF entities into the domain layer as well, discard clean architecture, and call it a day? Evetually, you will need transactions and look at what happens to IApplicationContext. There will be additional ITransaction stuff to expose. I think the main drawback is that developers have access to all tables and all their persistence methods in all handlers. I've seen this turn into an awful mess when junior developers get busy. I think clean architecture shines when moving away from CRUD to DDD, ES/CQRS with commands and queries. That being said, when going cloud native there are even better options.
Well, I don't work with juniors. And when I do, I educate them. I won't merge a PR unless it's up to standard. And you'd be surprised how quickly they learn 😁
Thanks. Great video. If I have a webapi project that is call the AddPersistence dependency injection in Program class "builder.Services.AddPersistence()", how is the configuration passed?
From my perspective this approach clearly breaks the Dependency Rule of the Clean Architecture 😉But as you rightly pointed out: this is a trade off decision. I see the point of being pragmatic in projects with just a few developers and few thousands of lines of code but for bigger projects personally I would rather follow the Dependency Rule more strictly.
Why do you give it a default value ? on some things i don't get it they are default to begging with? Its just more code and for me more code is less haha
@@MilanJovanovicTech cancellationToken = default? is it not the same with out giving him = default? I keep seeing people doing that on int a = defualt... to be 0 when is zero for example haha
My biggest concern here is that you have business logic mingled with db logic now. You cant really unit test this anymore. Sure, you can do in memory db context, but why? Id rather just call a repo that then either inplements ef core or dapper as the query so i can unit test without worrying about setting up a db for them.
Its very funny when almost everyone will argue that "what will you do when you need to change your database?". Like wtf, doing that not only affects the code but the data as well which is a nightmare to migrate. Essentially youre breaking the whole system if you do that so basically that arguement is an over engineering and premature optimization
true you don't have to abstract ef core away but it isn't really clean architecture at that point is it? your application layer is now dependent upon an infrastructure layer technology.. What if you wanted to use dapper instead? now not only would you have to create new implementations but you'd also have to create a new abstraction haha.. The cleanest architecture will have an abstraction around your unit of work and repositories. And the implementations of those will be in the infrastructure layer. Easily swappable without having to re build your application layer. Just my opinion.
@@MilanJovanovicTech No swapping database technology isn't easy there is a migration that takes place and that is why ef core is good since you can change providers easy but your code architecture doesn't support that event should it take place. Not only that, say you aren't changing your database technology and are only changing the technology used to interact with that database. you are making it so that you have to change your application layer code which in my opinion should be changed in the infrastructure layer. not the application layer.
By skipping that abstraction you definitely get rid of the need for much boiler plate code but by adding the abstraction it makes dependencies much more mockable and in the end your application as a whole is much more testable, maintainable and scalable over time. The boiler plate can also be abstracted into common libraries (nuget package) if you are really worried about rapid development. This is what I do for all of my apps.
Yes, let's make our application layer dependent on EF and implement data logic there.. EF (and Dapper) are not good things to have a hard dependency on because neither can fix everything. It's better to be futureproof and separate implementations from concepts. This could work for smaller (microservice?) applications but for larger monolithic business applications with lots of complexity and large domain models this is a hard no-go for me.
You are making a critical mistake. While you do create an IApplicationContext interface, you expose DbSet in that interface. This means that when you use this interface in your application layer, you will implicitly require references to Entity Framework in your application layer. This violates one of the principles of clean architecture, which is to remain agnostic to any external dependencies. It is important to remember that both your application layer and persistence layer are part of your core. What you have done is a very common mistake due to a lack of clarity about these concepts.
@@MilanJovanovicTech I don't want to get into controversy with you, your contributions are good, but I don't think I share an incorrect practice. deliberate compensation? With that you break a fundamental principle of clean architecture. There is no compensation to back it up. your core(persistense+application) if you decide to migrate it to an application that does not use EF what will you do? since when you use the interface it will ask you to reference EF
Sorry, I have to comment, what's with all the stupid faces in the thumbnails? Do you not consider your videos good enough to attract views? I think the content should bring people, it's why I started, subscribed and even grab your emails. But I'm rethinking viewing as I feel I'm being baited into watching and that normally gets an instant dislike from me (as do shorts). Personally, I think you provide a great channel and some really informative content, and I've said so to the RUclips polls that often appear under your videos. Though I've not learnt anything new, you have definitely reinforced many of my current engineering practices.
Hey Allan, I feel ya. Let me explain, there's a very good reason. On the one hand, I'm having a lot of fun making these thumbnails 🤣 On the other hand, now that I'm a full-time content creator I make a living out of this. Which means I need to prioritize: - Channel growth - Attracting more viewers The "stupid faces in the thumbnails" help that out a lot, whether you like it or not. It's basic human psychology also. This video has the highest CTR of any of my previous videos, and I knew it would.
For people who think you will never swap out EF Core for another ORM. It's not a problem until it is.. Why not just code around that possibility to begin with? This is the definition of writing maintainable and scalable applications.. is it not?
@@MilanJovanovicTech because it's a very easy thing to do that enhances maintainability and whoever inherits my code will thank me when/if they have to make that change. By easy thing to do I am meaning that you already have common boilerplate abstracted into your own private nuget feed. it doesn't slow down development I've found.
I do admit however that ef core is the most widely used orm that I have worked with. And it is my favorite. I don't have anything against ef core. My design is specifically to make the application more modular and loose coupled that is all.
@@MilanJovanovicTech well, yes. But I think it is significant. You need to stay consistent to have the same type of unit tests for all the parts of the application. If they would became ugly just for the sake of quick coding experience, you would feel the disadvantage long after point of no return. So, I would prefer repositories.
Want to master Clean Architecture? Go here: bit.ly/3PupkOJ
Want to unlock Modular Monoliths? Go here: bit.ly/3SXlzSt
The DB Context interface is basically an IUnitOfWork, whereas the DbSets act as repositories. I think this is why there is a lot of debate on not using Repositories with EF.
Yes, that's one of the reasons, and also what I mentioned in the video
I think what Milan showed was a way to sepparate the repository aspect from the IoW aspect by defining interfaces that act as facades over EF. I this is possible to have two interfaces, one that only defines the DbSets and another that only implements SaveChangesAsync that can be used only in use-case implementations.
Well no, it's a unit of work pattern tied to EF. But it's okay if you know the consequences.
@@mihaiga I totally agree with you, because the dbset is tied to ef, therefore another interface will be required to house properties for other orms or nosqls. Also, an interface particularly for savechanges is required since it is tied to ef (interface segregation principle in SOLID).
@@ibiballer2003 right another interface for another implementation of orm. this doesn't make sense to me to design the app this way.. I look at the application layer as a module with a bunch of sockets like a power strip. the interface contract creates a unique socket formation and the implementations are modules you can plug into them. following that logic why would you design your application to swap out the plug. instead you could design your app to be more universal and instead plug many things into that socket without needing to change the socket or under the hood wiring / circuitry.. Just my opinion.
How you handle the unit testing if use IApplicationDbContext ?
DbSet is mockable, as Jennifer noted. And you can also easily run integration tests.
@Jennifer K Oh yeah, coming to that. Just trying to follow some path I have in my head in terms of topics.
You can do it using WebApplicationFactory (Microsoft.AspNetCore.Mvc.Testing), no need to use mock
But it's not great. Your contract is now the full IApplicationDbContext that you need to verify and check in your tests. Really breaks the Interface Segregation Principle.
@@paarma1752 Indeed. Lots of tradeoffs here.
It's a great approach to use in CRUD/simple modules. In complex domains, you should use repositories as they are part of the domain
What changes for a complex project?
@@MilanJovanovicTech repositories guide others on how to work with a given entity. Some examples:
1. When you use an aggregate pattern you should access an entity only through the aggregate root. The repository pattern helps you to enforce it
2. Repository can tell you whether an entity can be deleted or it abstracts a way to delete it (it's helpful with soft deletes)
3. There are domain problems where entities can be create-only and should never be updated
4. Repository encapsulates re-creating objects correctly from the database (helpful with eager loading related entities using.Include() etc)
Of course, each abstraction adds complexity so using repositories, aggregates etc. should be justified. Personally, I use both approaches, even in the same application. Different modules have different complexity and needs
100% agree with Piotr. In DDD the repository pattern has it's place. In big projects having small agregates and eager load the entire graphs is a good idea, forces you think about where should be the boundaries between them instead of everything reference everything, lazy loading pulls 30% of the database and devs complain about the ORM being slow.
Tbh in many cases repos and uows hide many underlying operations so people start using repo operations “because they are there” but under the hood they can easily execute a lot more operations than they need. In many cases I’d actually prefer to have the access to dbcontext and also see exactly what’s being executed.
The repository pattern is a really misused and misunderstood pattern.
If you’re applying DDD, they are vital when working with aggregate roots. To understand the repository pattern, you need to understand the role of aggregate roots in DDD. If you don’t do DDD, then I totally agree, you don’t need repositories, but if you apply DDD, then this is a totally different question and not applicable to what you’re trying too demonstrate here.
The major reason for this confusion is that the vast majority of the examples you see on the web of repository implementations, are not applied on aggregate roots that adheres to the rules of DDD.
This is my favorite approach, with a few slight changes. In the interface I define for example: public dbSet orders {get;} (only get) in the implementation the Set is assigned. Also add public DatabaseFacade Database { get; } for transactions.
Get can be also implemented as { get => Set(); }. With this approach you don't need setters at all and this also doesn't generate null reference warnings.
That's a great addition!
I remember you asking me why you even would do EF Core directly. It depends on the use case. But unless you really need to switch out EF Core sometime or even creating mocks this would be totally acceptable. But if you are doing DDD, you should consider creating repositories for your aggregates - to get a standardized interface that is mockable - and use the DbContext directly (or via an interface) for just accessing data in a flexible way outside of aggregates.
Repository for commands - DbContext for queries?
I agree.
An important drawback is that the application project is coupled with EF and using a different ORM without rewriting the project is not an option anymore. In most scenarios it can be a valid approach anyway.
How many times have you ever be in need of changing database, let alone ORM or adapter?
I agree with the argument, but from my experience YAGNI. And I've been the one forcing abstractions. Should we rethink our design?
@@LeeDale1981 I agree.. What is the purpose of the abstraction with reference to DbSet to begin with?.. couldn't you just inject the context directly? isnt the abstraction with reference to DbSet just a leaky abstraction?
I think this approach is very pragmatic. Sometimes you create abstractions by using repositories and at the end of the day, if you switch to a different data store (i.e. a document database), you end up having to change your application layer to some degree. By using this approach you get speed by introducing some coupling (to EF), which is an abstraction already so it may not be a problem for many applications.
Yup, it ends up being too much hassle
EF Core also supports non-relational datastores as well. It's not limited to SQL/Relational data stores.
When you directly use the DbContext in your application layer, a major issues I see is in your unit tests as you face several challenges related to mocking of the dbcontext, the only real option is an In-Memory Database. Where you now have more of a integration test than a unit test.
In-memory DB is anything but an integration test. It's still a unit test.
@@MilanJovanovicTech When you use an in-memory database, you are testing the interaction between your code and the database, albeit a simplified one. This introduces a dependency on database behavior, which is typically beyond the scope of unit testing. You are bluring the lines between unit tests and integration test.
Also some versions of EF mocking the dbcontext is a massive pain.
@@thealbear3629 It's not a database. It's the same as an in-memory list. There are no translations to SQL etc.
@@thealbear3629 This I would consider integration testing: ruclips.net/video/tj5ZCtvgXKY/видео.html
Since it's using an actual database in a Docker container
Hello. I'm trying to create an architecture. But the repository doesn't make much sense to me. And basically against SOLID. What's the harm in using this approach on large projects? And do you think there is flexibility for variations? And is there any benefit to using mediatr and cqrs without using separate databases for read and write?
I like CQRS for the logical separation, more so than the physical separation at the database. It's a personal preference however.
As for using this in a large project - you'd need to solve one problem: query reuse. Then it's fine.
Honestly, I do both in my application layer.
I inject a class that holds all my repositories, so that I can easily use the specification pattern, since my repositories can query by specification.
In cases where I need some rapid development and get things done, that class also holds a property that gives me my DbContext directly and I can use EF Core as I normally would.
After the test phase, I push the code to the repository and revert back to a 'clean architecture' code.
This was a problem with the initial Jason Taylor Clean architecture example. He also decided that the dependence on ef core was something he could live with.. I've since improved upon that initial source and have been able to abstract that away using IDatabase and IRepository abstractions.
But you're still depending on EF Core with IDatabase?
@@MilanJovanovicTech No you create your own IDatabase abstraction that has many IRepository sets has no dependence on EF Core. your application layer should have no reference to the ef core library.
@@z_prospective160 But you're probably using EF under the hood?
And thus conforming the IDatabase interface design to how EF works?
I wasn't clear by using the name IDatabase since ef core has an IDatabase abstraction defined. I was saying that you create your own base IDatabase abstraction to inherit from. This abstraction would have unit of work methods such as save changes and begin transaction etc.. then you can create extensions of that abstraction like IMyApplicationDatabase : IDatabase and that abstraction has the repositories that your database actually has. so instead of referencing ef core DbSet you instead reference IRepository. Then in your infrastructure layer "Persistence Layer" you have many implementations of IRepository such as maybe EFCoreRepository or DapperRepository etc.. depending on which technology you want to use for interacting with your database.
@@MilanJovanovicTech no not really.. the unit of work abstraction should have methods pertaining to the persistence. it isn't conforming to any implementation it just provides the interface for persisting changes to your database. This means also that in your application layer you can't rely on ef core change tracking.
Your videos area awesome! I think it worth to use this for small/medium projects. 👏
Thanks!
One more good approach for discuss. Thanks!
But i still don`t understand why people talk about wasting time for implementation repositories, just use existing implementation like Ardalis.Specification or create own implementation for future. If dont like Repo- use this approach.
Specification is something else
How should a read-only database context be interfaced? Are you considering disabling the lazy proxy?
Configure it with QueryTrackingBehavior.NoTracking
IDbSet represents a collection of Entities just like the repository pattern Entails. However, it's an Interface specific to Entity Framework. Using this Interface directly isn't a very clean practice as it leaks the IDbSet obstruction from Entity Framework and into our application layer. In addition, exposing all of the repositories and the save method in the single IDatabaseService interface potentially violates the interface segregation principle.
I don't mind the EF dependency
The only one alternative to EF is Dapper, we use dapper when need performance. Dapper makes a difference but only with long stored procedure which actually cover more than one functionality.
So i think this change would be rely on replacing many functions in C# to sql procedures and repository would not be needed still.
You can also run exactly the same queries with EF Core. Dapper is kind of obsolete 🤔
Another good benefit of using repository and unit of work pattern is that you can easily mock repositories to help with unit testing.
Agreed, but that only makes sense for testing some business logic
Why DbContext Interface in Application lvl and not in Domain? In repository pattern we define repository interface in domain.
I don't want to introduce any libraries at the Domain level
Hi, Milan. I have another question.
I try to follow DDD, which involves having entity methods like User.ChangeStatus(…), User.Restrict(…). The problem I encountered is that I have no idea on how to properly map my REST CRUD interface to that.
Also, in CRUD-like interface I’d like to make use of JsonPatch, but it breaks invariants by requiring public setters. After applying Patch to my Entity I have to run a Entity-wide Validator, which is rather a CRUD option, not DDD one.
I consider using Task Based UI, what do you think?
I have noticed Ardalis had the same situation in his DDD eShop project. His solution was to use PUT, have general purpose APP Service Update(…) method which selects every PUTModel property and maps it to Entity property by calling Entity Domain Methods for each. Like;
user.ChangeUsername(); // even if it was not changed in PUTModel
user.ChangeAddress()
…
Just name the endpoints based on the domain operation, you end up with many endpoints but that's fine
i've got a question: If you've got a lot of simple queries like "GetOrder" in this case, which doesn't have any use case type logic- just data retrieval. Is it really bad to have dbContext/unit of work available in the presentation layer? I have got ViewModels which take in take in a domain entity in a constructor and map it.
You would write the logic directly in the controller endpoint?
@@MilanJovanovicTech enough said... i will have to move it to the application layer 😅
I would also use IDbSet in the interface and only reference the EFCore.Abstractions in the Application project.
But then the implementation is a little more verbose 🤔
@@MilanJovanovicTech How so? I think EF core team recommends using
public DbSet Customers => Set();
over
public DbSet Customers { get; set; }
Now anyway. So the first form would slightly change to:
public IDbSet Customers => Set();
@@pilotboba IDbSet is not available in ef.core abstraction. you should refrence ef.core
@MilanJovanovicTech is it always the case where Infra models/ Db models will be same as Domain models?
Not always
@@MilanJovanovicTech what we can do in that case?
Reusability of same query will be difficult in this case as compared to repository.
Extension methods? 🤔
I was thinking myself how to solve this also.
@@MilanJovanovicTech Extension Method encapsulating the specification for complex query
in 1:20, in Order Class, why do you assign Guid.NewGuid() for OrderId and LineItemId. Shouldnt it be generated by DbContext after SaveChanges?
I like to generate mine on the client side
Why not add a reference from application to infrastructure and leave the interface IDbContext in the infrastructure layer?
Wrong direction of dependency
Thanks for your toturials ❤, Could you please give me a source(c# implemenation,...) about Generic repository interface that capable to switch from sql DB to document DB?
No, sorry
what about any book introduction or toturial ?@@MilanJovanovicTech
Hi Milan what theme do you use for visual studio?
VS Dartk theme + ReSharper syntax highlighting
I dont know if you have handled it elsewhere, but our domain objects are not eimilar to thr database wnd 2e can't simply change.
Read one item has different tables. And those tables are also used for other models.
How would you deal eith such as thing?
Charging the database is not really an option
Check out the Anti-Corruption Layer: learn.microsoft.com/en-us/azure/architecture/patterns/anti-corruption-layer
This approach is fast and pragmatic for sure. I think this works really well on smaller projects or in a small team. One thing I kinda miss is code reusablity (maybe you or somebody else could give me a hint here ;-)). When the logic gets more complicated, the code starts to get more and more smelly. Especially when working within a team with different experience levels. Some team memvers start creating some sort of services to reuse code... others extensions... others just implement everything within the handler. So my biggest issue right now is probably maintainability.
That's when I would prefer to use an additional layer (call it repository-, adapter- or whatever layer) so everyone just knows where to "place the code".
It's really funny because I (and my team members) started to implement this approach while also encountering the issues I've mentioned :D any help or ideas would be really appreciated
My thinking was either:
1. Extension methods to encapsulate queries
2. Static query clasess
3. Repository/service
Any one of these will work just fine.
Unless you already know the whole architecture (which is rarely the case), I believe that procedural (in the handler) programming is the best because it's gives you the most fluid code. The tradeoff is conciseness but that's OK in my opinion because clarity suffers not so much. However, if you don't refactor that procedural code into proper classes, then you will end up in a bigger mess. So it takes expertise to guide the project
@@Euquila agree. Refactroing is the key, but some people are lazy to do it, some do it religously
Try to cover handler by unit tests, especially if your db query would has include(). You would feel a lot of pain
You can always use a real DB and not have to worry about it
@@MilanJovanovicTech then it becomes an integration test, not a unit. Moreover, you have to care about real DB in your CI pipelines which is not convenient.
Hello, Milan.
I've been following your videos.
They are excellent content.
Thank you for sharing knowledge.
In my opinion, this is not a very cool approach when it comes to writing (commands).
I prefer to go through the repositories and unit of work.
However, when it comes to reading (queries), I find it quite interesting.
I would use it in the QueryHandlers to return QueryResult - Response objects using EF Core projections.
It would bring excellent performance gains, and we wouldn't need to use another DTOs with Mappers, returning the projection directly to the QueryResult.
(avoiding unnecessary database overhead).
I'm generally with you, but I think it's important that I talk about different perspectives from time to time
I used to use this approach frequently in old EF (before Core) as it was very unlikely we'd be changing ORM but now with Dapper providing better performance I like to keep my options open. I don't think there's anything wrong with this approach though if you're sure you want to stick with EF.
You can also run exactly the same queries with EF Core. Dapper is kind of obsolete 🤔
Hi. I think about learning C# with .NET and I use your videos to explore. Also it helped me a bit with the DDD and CA concepts.
I have a question. I often see you making methods asynchronous, but then you await for the results anyways. What's the reason?
Async IO: learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/
Could you make a video about multitenancy using a single database? Or a series of videos on this matter. Would be interesting to see how you'd implement it :)
Yes
Multitenancy using a single DB throws a lot of issues including but not limited to security, data corruption, performance, individual tenant backup etc. etc. etc. I strongly recommend using separate DB per tenant, even if you think you have it under control with your code. Just saves a lot of future headaches.
@@jackreacher4945 that is totally TRUE.. this advice is worth GOLD
What really buggers me is the ProjectExplorer of Visual Studio, not being able to create a Folder in the Directory on my Machine by Default , instead just referencing one. So in the csproj it looks well sorted, then u look via win explorer and have nightmare of a structure, especially when renaming folders or Projects. Hotkey F2, i would guess will do the same as context menu> click-> rename, but lol it doesn't. So also the namespaces easily get twisted.... Sry. just wanted to spout that. Even if wrong place. :D
I read every single word!
Repositories at the end of the day are a design pattern. It is the developer that decides if they want to implement it or not. If you want to have a feature map structure aligned with the feature that's been developed, a repository pattern would be in violation of the basic principles. So it would make sense to use commands instead.
This all said tho, a feature map structure on the domain level has a tradeoff, especially in the architecture where entity framework would be dependent in all layers. I see too much tech dept to implement it that way.
What would you propose as an alternative?
Is this part of a series? The eShop? Thanks for sharing! I normally don't use EF Core (We use a developed in-house micro-ORM) but after seeing this, it looks nice clean and easy, will have to start a test project to try it out some more.
Kind of, I don't go over everything step by step, but working on the eShop project for a while now
Assuming you have more than one DB used (let's say SQL and Mongo) - a repository pattern will still be better fit.
Also assuming you have an existing application where you choose to move away from EF or change DB or incorporate other methods of connecting to the DB (for performance as an example) - having all this in a repository will make your life much easier.
Lots of assumptions 😁
@@MilanJovanovicTech Assumptions = Prepares - which for large projects can save a lot of time down the road
I just thought of this now too.. if you are going to reference ef core from your application layer then why not just inject the ApplicationDbContext class directly? I'm not sure what value the IApplicationDbContext adds or what is being abstracted away. It just seems like a leaky abstraction at this point. By leaky abstraction I mean it exposes elements of the implementation that should be abstracted away.. cough cough.. DbSet type.
Yep
DB Context is a UoW/Repository pattern implementations at once. That reminds me of NESTJS (speaking of the NodeJS world) where you use directly a repository involved with its default ORM (typeorm) and it's almost the same as how you used EF.
Interesting topic :)
I'm not as familiar with how other languages do it 😁
I think the main reason to create repository abstraction is to alow the change ORM without impacts or code review. Moreless, repository is a domain pattern. So, why not?
But changing the ORM will never be _just switching the implementation_. There will always be coupling to how that particular ORM works.
how to use caching with these approach?
Good point! You can cache on the query (request) level, for example with a MediatR pipeline. Or just create a simple service to solve caching.
I know I'm late to the party, but I just watched this video, and it's still useful ;). While abstracting `DbContext` is debatable subject. I generally like to either stick with `DbContext` and implement service classes out of it, or implement the interfaces and then hookup the Dbcontext on separate layer. The later approach separates the data provider, which means easy to change the data provider, or have multiple providers. If there is any reason to use repository with EF, then what I would do is move EF to a separate project, and keep its context along with properties internal, and only expose the repositories. this way, the consumer will be forced to only use the repositories, and don't have access to the underlying context (can bypassed using Reflection tho 🤪 ).
Great video as always I really like watching your videos, don't you ever stop 😎👍
What do you think about splitting EF/repo's for reads/writes?
@@MilanJovanovicTech you've mentioned that in some of your videos (I'm a good watcher ;)).. To be honest, I've never worked in a project uses that pattern. I think it would enforce the security isolation; but I can't think of a use case to support that thought! Maybe my brain needs a new software update 😣.
Bolji si od Chapsasa, bravo.
Veliki kompliment za mene, hvala puno! :)
My issue with this is unit testing. I can't find a good way to mock EF Core calls without using a repository layer.
So don't, use an integration test
Amazing video as always, can you please create a full course about DDD from start to finish? maybe even not in RUclips but in Udemy. It would be something I'm sure everyone that takes application architecture seriously would like to invest in.
I'm planning a "Production ready API" first, then maybe one for DDD
@@MilanJovanovicTech sound amazing, will you also include setting it up in the cloud from start to finish with best practices?
Great tech videos, thanks Milan. I have a doubt please clarify how to inject repository to these domain models? Or should we avoid that
In this video, I'm arguing against using repositories
Not keen. Having to change the Application Layer frequently undermines a key benefit of Clean. EF core will likely need frequent updates to dependencies. Plus it undermines training of trainees or newcomer junior devs who would see the dependencies and think they can start adding more and think they were trained wrongly to keep dependencies out of inner layer.
All of these points can be easily addressed
Hi Milan, thanks for all great work I am aspiring junior .net dev and I learn a lot from you.
My question is: this approach is only possible when commands and queries are in the application layer. However, I have heard opinions that they belong to Core/Domain layer.
What do you think?
Because otherwise, it's not really possible as the core layer doesn't have any reference to infrastructure layer. Because of that, we cannot use infrastructure types there.
At some point, it becomes a matter of personal preference. What matters is that the code works, and provides the required functionaility
@@MilanJovanovicTech thank you Milan! Keep up the good work
Easy replacement of SQL with NoSQL is not always possible. If you replace relational DB with a document-oriented one, you will probably have to re-write repositories and logic, as the document structure will differ from the relational one.
Agreed
As you say, you added EF Core dependency directly to the Application (logic) layer. This means you just got rid of the repository layer basically.
That's the idea basically
I don't agree much with this approach as you are adding a direct reference to entity frameworks in the application project since while using an interface, within it there are DbSet. I prefer the abstract repository approach to decouple the application layer from the infrastructure layer. What do you think?
I'm arguing exactly against that, since for simple projects there is no added value. However, I'm a fan of the 'specific repository' pattern with DDD
can you make a dapper setup tutorial?
Yes!
How is your VS so fast, not laggy?? Share some tips please
Buy the latest AMD processor? That helped me 😅
Imagine if you didn't use EF Core? What a life
A sad life indeed
I have to say that I'm not a fan of using EF Core. To me, unless you implement it within the repository pattern, you are always tied to using it as a provider. I also don't like the migration strategy of scaffolding via a command line tool, I like to code my own migrations whether in SQL or using a tool such as FluentMigrator. I quite like using Linq2DB within my repositories as I can automate the mapping based on the FluentMigrator table setup. For the most part, I find myself dealing with simple CRUD operations so that approach works fine. Sometimes there may be some more complex queries that needs to be faster, for example running a complex report, and for these I might add a separate interface and deal with them in a different way - e.g. executing a stored procedure or custom SQL.
I fully support your approach. There are many ways to write great software :)
Clean or not that is just opionions as you said. It is fast in the beginning, but scale really bad a year in a project. I am using repositories becuase I know where I get my data, I don't care if it is EF or dapper or if I need to change that to an api or another database in the future or just update the query I know where to look. To many projects that do not use repository implementation have the database code spread out everywhere with dublicated code.
You can easily sole duplication with extension methods. Right?
I think it is fine to implement as this; you are injecting interfaces into the controllers, etc., not the dbcontext directly.
It's a pragmatic approach, for sure
Maybe it's just the habit but feels so weird not using repositories, like something is not ok xD
Me too, but I have to step out of the comfort zone so I can bring you good content 😁
to be honest, with repositories you just reimplement LINQ for EF. That's it, it's a waste of time. On top of that, what does you repository return, IList? If so, sooner or later you will end up with code that pulls multiple records to get a single one in the end. If you return IQUeryable, what's the point of repository? Unless you do it just for unit testing, it's pointless
The only use case(s) for the repository pattern that I see is when you want to mix up Dapper / Norm and Entity Framework Core (as in, when there are a few cases where you have to write your own raw queries that won't be mapped to a DbSet).
For anything other than that, I believe one should stick with NOT implementing the repository pattern, but that's my 2 cents only.
With EF Core 8, Dapper/Norm as busted
The key concept in clean architecture is that dependencies only point inwards. Since EF is for persistence, it is part of the infrastructure layer. In this example, EF dependency is brought into the application layer, which breaks the first rule of clean architecture. If initial development speed is a priority, why not add EF entities into the domain layer as well, discard clean architecture, and call it a day?
Evetually, you will need transactions and look at what happens to IApplicationContext. There will be additional ITransaction stuff to expose. I think the main drawback is that developers have access to all tables and all their persistence methods in all handlers. I've seen this turn into an awful mess when junior developers get busy.
I think clean architecture shines when moving away from CRUD to DDD, ES/CQRS with commands and queries. That being said, when going cloud native there are even better options.
Well, I don't work with juniors. And when I do, I educate them. I won't merge a PR unless it's up to standard. And you'd be surprised how quickly they learn 😁
Thanks. Great video. If I have a webapi project that is call the AddPersistence dependency injection in Program class "builder.Services.AddPersistence()", how is the configuration passed?
builder.Configuration
From my perspective this approach clearly breaks the Dependency Rule of the Clean Architecture 😉But as you rightly pointed out: this is a trade off decision. I see the point of being pragmatic in projects with just a few developers and few thousands of lines of code but for bigger projects personally I would rather follow the Dependency Rule more strictly.
Of course, we make trade offs every day 😁
Why do you give it a default value ? on some things i don't get it they are default to begging with? Its just more code and for me more code is less haha
Give what a default value 🤔🤔🤔
@@MilanJovanovicTech cancellationToken = default? is it not the same with out giving him = default?
I keep seeing people doing that on int a = defualt... to be 0 when is zero for example haha
My biggest concern here is that you have business logic mingled with db logic now. You cant really unit test this anymore. Sure, you can do in memory db context, but why? Id rather just call a repo that then either inplements ef core or dapper as the query so i can unit test without worrying about setting up a db for them.
Or you can do actual DB tests with Docker: ruclips.net/video/tj5ZCtvgXKY/видео.html
Its very funny when almost everyone will argue that "what will you do when you need to change your database?". Like wtf, doing that not only affects the code but the data as well which is a nightmare to migrate. Essentially youre breaking the whole system if you do that so basically that arguement is an over engineering and premature optimization
Not to mention migrating from a relational to some other sort of DB...
You should credit Jason Taylor as this is from his clean architecture template
Oh, did he invent this?
true you don't have to abstract ef core away but it isn't really clean architecture at that point is it? your application layer is now dependent upon an infrastructure layer technology.. What if you wanted to use dapper instead? now not only would you have to create new implementations but you'd also have to create a new abstraction haha.. The cleanest architecture will have an abstraction around your unit of work and repositories. And the implementations of those will be in the infrastructure layer. Easily swappable without having to re build your application layer. Just my opinion.
Persistence ignorance is more related to the Domain than to application.
And you can never "easily" swap databases 😅😅
@@MilanJovanovicTech No swapping database technology isn't easy there is a migration that takes place and that is why ef core is good since you can change providers easy but your code architecture doesn't support that event should it take place. Not only that, say you aren't changing your database technology and are only changing the technology used to interact with that database. you are making it so that you have to change your application layer code which in my opinion should be changed in the infrastructure layer. not the application layer.
By skipping that abstraction you definitely get rid of the need for much boiler plate code but by adding the abstraction it makes dependencies much more mockable and in the end your application as a whole is much more testable, maintainable and scalable over time. The boiler plate can also be abstracted into common libraries (nuget package) if you are really worried about rapid development. This is what I do for all of my apps.
Yes, let's make our application layer dependent on EF and implement data logic there.. EF (and Dapper) are not good things to have a hard dependency on because neither can fix everything. It's better to be futureproof and separate implementations from concepts. This could work for smaller (microservice?) applications but for larger monolithic business applications with lots of complexity and large domain models this is a hard no-go for me.
How would you approach this on the query side?
Just don't write actual implementation in Application layer, expose interfaces and let Infrastructure implements them
Exactly
You are making a critical mistake. While you do create an IApplicationContext interface, you expose DbSet in that interface. This means that when you use this interface in your application layer, you will implicitly require references to Entity Framework in your application layer. This violates one of the principles of clean architecture, which is to remain agnostic to any external dependencies.
It is important to remember that both your application layer and persistence layer are part of your core. What you have done is a very common mistake due to a lack of clarity about these concepts.
Not a mistake - a deliberate tradeoff
@@MilanJovanovicTech I don't want to get into controversy with you, your contributions are good, but I don't think I share an incorrect practice. deliberate compensation? With that you break a fundamental principle of clean architecture. There is no compensation to back it up. your core(persistense+application) if you decide to migrate it to an application that does not use EF what will you do? since when you use the interface it will ask you to reference EF
It's not solid, you are exposing all the dbSets with one interface.
Works well for simple projects
Sorry, I have to comment, what's with all the stupid faces in the thumbnails? Do you not consider your videos good enough to attract views? I think the content should bring people, it's why I started, subscribed and even grab your emails. But I'm rethinking viewing as I feel I'm being baited into watching and that normally gets an instant dislike from me (as do shorts).
Personally, I think you provide a great channel and some really informative content, and I've said so to the RUclips polls that often appear under your videos. Though I've not learnt anything new, you have definitely reinforced many of my current engineering practices.
Hey Allan, I feel ya. Let me explain, there's a very good reason.
On the one hand, I'm having a lot of fun making these thumbnails 🤣
On the other hand, now that I'm a full-time content creator I make a living out of this. Which means I need to prioritize:
- Channel growth
- Attracting more viewers
The "stupid faces in the thumbnails" help that out a lot, whether you like it or not. It's basic human psychology also. This video has the highest CTR of any of my previous videos, and I knew it would.
Your video about repository pattern lasts 9 minutes. This video lasts 10 minutes. Is it realy faster than repository pattern?)))
It turns out it's 1 minute slower. Who knew 🤷♂️
you will some reusabilit? example you need to call that customer.getid everytime you need the same result
Extension methods, or another abstraction
For people who think you will never swap out EF Core for another ORM. It's not a problem until it is.. Why not just code around that possibility to begin with? This is the definition of writing maintainable and scalable applications.. is it not?
The real question is. Why *do*?
You won't need it in 99.99% of cases
@@MilanJovanovicTech because it's a very easy thing to do that enhances maintainability and whoever inherits my code will thank me when/if they have to make that change. By easy thing to do I am meaning that you already have common boilerplate abstracted into your own private nuget feed. it doesn't slow down development I've found.
I do admit however that ef core is the most widely used orm that I have worked with. And it is my favorite. I don't have anything against ef core. My design is specifically to make the application more modular and loose coupled that is all.
I don't like this, because unit testing will require some extra steps to create.
Okay, is that the worst of it?
@@MilanJovanovicTech well, yes. But I think it is significant. You need to stay consistent to have the same type of unit tests for all the parts of the application. If they would became ugly just for the sake of quick coding experience, you would feel the disadvantage long after point of no return. So, I would prefer repositories.
This is not clean architecture, you now have tight coupling with EFCore. Nothing clean about it :)
Sure, I call it Pragmatic Clean Architecture