And I’ve found that this simple name change significantly reduced the cognitive load required to use that component and to verify that it was being used correctly. It often starts off easy (PerWebRequest or Transient lifetime for everything which suits a simple web app well) and then descends into more complexity as console apps, Windows Services and others inevitably make their appearance. There is however a number of other issues you will run into with an injected DbContext regardless of the architectural style of your application. The answers here aren’t obvious and will require you to pour through your DI container configuration code to find out. And as we’ve seen earlier, getting this configuration right isn’t as trivial as it may seem at first sight and may end up being fairly complex and / or subtle. There are several key behaviours of Entity Framework you should always keep in mind however.
The only reliable method to correctly manage the database transaction lifetime with NHibernate is to wrap all your service methods in an explicit database transaction. This is what you’ll see done in pretty much every NHibernate-based application. As a result, it’s advisable to avoid managing the lifetime of DbContext instances separately from business transactions.
Create an ASP.NET Core Web API project in Visual Studio 2022
If you don’t already have a copy, you can download Visual Studio 2022 here. In this article we’ll dive into DbContext in a little more detail, discuss the DbContext lifetime, and offer some best practices for using DbContext in Entity Framework Core. Saves all changes made using this context to the underlying database.
After creating the context and entity classes, it’s time to start interacting with our underlying database using the context class. However, before we save or retrieve data from the database, we first need to ensure that the database schema is created as per our entities and configurations. As you can see in the above code, the context class (EF_Demo_DBEntities) includes the entities as DbSet type for all the tables and views. The point that you need to remember is, whenever a class is included as DbSet type in the context, then it is considered an entity and then we can access this entity using the context object. It is also used to configure domain classes, database related mappings, change tracking settings, caching, transaction etc. If you force the creation of a new DbContextScope (and therefore of new DbContext instances) instead of joining the ambient one, your service method must never return persistent entities that were created / retrieved within that new scope.
DbContext Class in Entity Framework Core
But if you intend to use Entity Framework’s async query feature, this won’t fly. After an async operation, you will most likely find yourself in another thread than the one where the DbContext was created. In many cases (although not in all cases – this is where async gets tricky), it means that your ambient DbContext will be gone. This is fixable as well but it will require some advanced understanding of how multi-threading, the TPL and async works behind the scenes in .NET. Particularly if your application uses multiple DbContext, resulting in service methods potentially requiring two or more mandatory DbContext parameters.
With DI, we are able to create a DbContext instance for each request and dispose of it when that request terminates. The DbContext class in EF Core adheres to the Unit of Work and Repository patterns. It provides a way to encapsulate database logic within the application, making it easier to work with the database and maintain code reusability and separation of concerns. This class is inherited from the system.data.entity.dbcontext namespace. The DbContext is part of the EntityFramework.dll assembly and is installed separately using the NuGet package Manager.
DbContext instances should be disposed of (but you’ll probably be OK if they’re not)
As we’ve seen above, the responsibility of creating and disposing the DbContext lies with the top-level service methods. With this approach, the top-level service method not only creates the DbContext to use for the current business transaction but it also registers it as the ambient DbContext. The data access code can then just retrieve the ambient DbContext whenever it needs it. When the need to introduce multi-threading or move operations to background Windows Services inevitably arises, this carefully constructed sand castle often collapses as there are no more web requests to bind DbContext instances to. Chances are that most of your service methods won’t use the DbContext at all, particularly if you’ve isolated your data access code away in query objects or in a repository layer.
This makes creating a service method that combines the logic of multiple other service methods trivial. Remember that DbContext (just like Session in NHibernate) isn’t thread-safe. If you need to execute multiple tasks in parallel in a service, you must make sure that each task works against its own DbContext instance or the whole thing will blow up at runtime. This is impossible to do with the injected DbContext approach since the service isn’t in control of the DbContext instance creation and doesn’t have any way to create new ones.
Database Schema Creation in EF Core
In the following example, the student is removed from the database whose id is 5. The following code is self-explained, so please go through the comment lines. DbContext doesn’t start explicit database transactions for read queries. It instead relies on SQL Server’s Autocommit Transactions what is entity framework (or Implicit Transactions if you’ve enabled them but that would be a relatively unusual setup). Autocommit (or Implicit) transactions will use whatever default transaction isolation level the database engine has been configured to use (READ COMMITTED by default for SQL Server).
But using an instance-per-form lifetime in a desktop application, which you’ll often find suggested, is a lot more questionable and requires careful thought before being adopted. The above context class includes two DbSet properties, for Student and Grade, type which will be mapped to the Students and Grades tables in the underlying database. In the OnConfiguring() method, an instance of DbContextOptionsBuilder is used to specify a database connection string.
Changing existing objects is as simple as updating the value assigned to the property(s) you want changed and calling SaveChanges. In the following code, the last name of Ali has been changed from Khan to Aslam. The primary class that is responsible for interacting with data as objects is System.Data.Entity.DbContext. In order to be more flexible and frequent with releasing new features to Code First and the DbContext API, the Entity Framework team distributes EntityFramework.dll through Microsoft’s NuGet distribution feature.
Another issue (related to the previous one) that will inevitably bite you quite hard is that an injected DbContext prevents you from being able to introduce multi-threading or any sort of parallel execution flows in your services. It’s not the end of the world but it certainly complicates DI container configuration. Having stateless services provides tremendous flexibility and makes the configuration of their lifetime a non-issue (any lifetime would do and singleton is often your best bet).
What is DbContext
Alternatively, you can create DbContext instances via dependency injection (DI) by configuring your DbContext instance using the AddDbContext method as shown below. Similarly, you could instantiate a DbContextOptionsBuilder class and then use this instance to create an instance of DbContextOptions. This DbContextOptions instance could then be passed to the DbContext constructor. When working with Entity Framework Core, the DbContext represents a connection session with the database. It works as a unit of work, enabling developers to monitor and control changes made to entities before saving them to the database. We use the DbContext to retrieve data for our entities or persist our entities in the database.
- It also muddies your method contracts as your service method are now forced to ask for a parameter that they neither need nor use but require purely to satisfy the dependency of a downstream method.
- I would first say that the DbContext class relates to Entity Framework (EF), but then the question tags would suggest you figured that much out yourself.
- Any changes made to your entities, be it updates, inserts or deletes, are only persisted to the database when the DbContext.SaveChanges() method is called.
- Entity Framework’s default behaviour should suit the vast majority of business transactions.
- And I’ve found that this simple name change significantly reduced the cognitive load required to use that component and to verify that it was being used correctly.
- If services create their own DbContext instances via a factory, these instances can’t be injected anymore.
About The Author
admin