Entity Framework Core: High-Level Diagram
Vanasis Baboomi
Experienced ASP.NET Full Stack Developer with Advanced Database and UI Skills Ready for Exciting Opportunities
The below image illustrates the process of how a?LINQ?query is executed at a very high level:
Let’s take the below code as an example:
After the code at line number?3?is executed, only the step?DbContext Instantiation?is executed as?DbContext?is lazy, it will not do heavy stuff until you actually start using it.
Let’s continue our code execution, at line number?5, we start using the?DbContext?then a lot of things are going to happen.
Continue code execution, after?ToList()?is invoked,?Compile Query?and?Execute Query?take place too.
Now that you see,?EF Core?does a lot of things in order to serve your query, and you might think that’s why it is slower than?Dapper?or?ADO, luckily isn’t that slow because?EF Core?is smart enough to leverage caching a lot, so for the subsequent queries it will not need to do all the heavy steps again and again.
DbContext Instantiation and Initialization
Now we will take a deeper look inside the?DbContext?class to find out how instantiation and initialization steps work.
DbContext Instantiation
Normally, when working with your DbContext, you often start your query with a query root, you can use the generic method?Set<TEntity>()?or you can also predefine some?DbSet?properties to name the Sets and don’t need to specify the generic type every time you want to work with.
For example:
Now you can access a Set in 2 ways and both should work no differently to serve your query.
Hold a sec, you might be thinking when working with a class if you just define a property and never initialize it, oftentimes you will face the?NullReferenceException, so why does the code at line?10?never throw that exception.?
the answer is: DbSet?was initialized so we will never face the?NullReference Exception?here.
Now you might be wondering who did that? I know you already know the answer: EF Core, but how? Let’s dig deep into the EF Core source code next.
Let’s take a look at one of the DbContext constructors:
领英推荐
focus on line?130?where EF Core tries to initialize all the DbSet properties you defined in your DbContext
DbContext Initialization
Because?DbContext?is lazy, it doesn’t do heavy stuff until you start using it, when you start working with the DbContext, it usually requires one of the properties of the?IDbContextServices ContextServices?property.
let’s see how?IDbContextServices ContextServices?is initialized the first time it is used.
It creates a?DbContextOptionsBuilder?instance using the?DbContextOptions _options (line 425)?(the one you pass into the constructor or default if you use the parameterless constructor) and then calls the?OnConfiguring?method (line 427).
In our?BloggingContext?example, the?OnConfiguring?method will be invoked and the?Sqlite Database Provider?is registered here.
After the?Internal Service Provider?is created and cached, it creates a scope and resolves the?IDbContextServices, so basically each?DbContext?instance will have its own scope.
The internal service provider
EF will create a service provider (container) when an application using EF Core is started for the first time. EF Core is built in a service-oriented way, so this service provider is loaded with all the services that EF uses internally. EF uses the default implementation of?Microsoft.Extensions.DependencyInjection?for this service provider.
For most applications the internal service provider is an implementation detail of EF. Applications should not need to care about it at all.
Build a Model
EF Core uses a metadata model to describe how the application's entity types are mapped to the underlying database. This model is built using a set of conventions - heuristics that look for common patterns. The model can then be customized using mapping attributes (also known as data annotations) and/or calls to the ModelBuilder methods (also known as fluent API) in OnModelCreating, both of which will override the configuration performed by conventions.
Compile and Execute a Query
Entity Framework translates LINQ queries into SQL queries to retrieve data from the database. When you write a LINQ query in your code, Entity Framework parses the query and generates SQL statements to get the required data from the database.
Entity Framework uses an expression tree to represent the LINQ query, which is then converted into SQL by the provider (such as SQL Server provider). The provider then executes the SQL query against the database and retrieves the results.
The query execution process involves multiple steps including query parsing, query translation, query compilation, and query execution. Entity Framework handles all these steps behind the scenes to execute the LINQ query and retrieve the data from the database.