I am a newbie to Entity Framework and would like some clarification on some things. I understand the DbContext
such as pointing to a SQL database with a connection string. Within the DbContext
, you declare DbSet<perEachTable>
that you want / plan to expose and get data from, from said SQL database.
Now, you get into LINQ, and I understand some of link such as enumerable lists of things and looking for certain qualifying where condition entries.
Now, my bigger question and how EF queries. You have a DbContext
pointing to SQL Server. It has a table of say 250k customers. It has its primary key defined as Id
(or CustomerId
) which is expected. You want to query and lookup a customer based on the user's email address (common type of expected query). The customer table has an index on the email.
In the LINQ queries I have seen, it is referring to the DbSet
of whatever table and runs a where clause, such as
using (var context = new DBCustomers())
{
var query = context.Customer
.Where(c => c.EMail == "[email protected]")
.FirstOrDefault<Customer>();
}
My mental thinking is that the entire list of customers is being pulled down from its DbSet context. Then it runs the link WHERE
clause to look for email. I don't think I want to be pulling down 250k customers down every time just to LINQ iterate through them.
How is it that the WHERE
does not actually use the entire dataset of customers (especially as/when it continues to grow) and just optimizes based the indexes available and does NOT actually pull everything down.
Is this just a magic black-box being applied and EF just hands you the entry (or few if other more open query) the final entries that qualified.
I have also seen instances of EF Core using fully written SQL statements and parameterized which is what I am more accustomed to doing. Letting the SQL Server engine return the data based on the explicit criteria that best matches qualifying indexes.
Appreciate clarification on the underlying operations.
CodePudding user response:
I'm not an expert about EF but, no not the whole table is requested.
It doesn't return an IEnumerable
but an IQueryable
it will generate an SQL query based on the linq statement and executes it on the sql-server when it is iterated by (for example a foreach loop).
You can get the SQL query by using:
var query = context.Customer.Where(x => x.Id == 1);
Console.WriteLine(query.ToQueryString());
CodePudding user response:
Your code DbSet<T>.Where()
is calling the Queryable.Where()
extension method, not Enumerable.Where()
.
Enumerable.Where
returns an enumeration that will step through the underlying enumeration, applying the filter on each item.
The purpose of Queryable.Where()
is very different. It returns an IQueryable
that captures a description of what you were doing. Each method helps you to build an Expression Tree, which is like a lambda function that has only been partially compiled.
An IQueryable
also implements IEnumerable
. When you start trying to enumerate the results, the expression tree is "compiled". Because you created the IQueryable
from a DbSet
, EF Core will take over this compilation process. Attempting to create an efficient sql statement and a function to convert the results into objects.
For efficiency, this function and sql will be cached. Each time you try to compile the same expression, most of the compilation process will be skipped.
CodePudding user response:
EF will construct a SQL query from your query
object and execute that on the server. That way only the result of the SQL query is returned.