Reputation: 825
I know how IQueryable
and IEnumerable
work. But today while I was revisiting those topics with an example.
Below are my questions
How many DB calls are made?
If I'm correct there are 2 DB calls, one with the where
clause and the other when Take(1)
is used.
public void GetEmployeesByDept(long deptId)
{
IQueryable<EmployeeDetails> empDetails = _context.EmployeeDetails.Where(x => x.Idseq == deptId);
// First DB call
var firstEmployee = empDetails.Take(1);
// Second DB call
Console.WriteLine(empDetails.GetType());
}
This is my explanation - but when I hovered over the empDetails
, I could see the expression contains two arguments
With the table
$x.Idseq == .Constant<TestProject.Program+<>c__DisplayClass2_0>(TestProject.Program+<>c__DisplayClass2_0).deptId
So,now when the execution finished the firstEmployee
, I hovered over the firstEmployee
variable, I could see the expression as below
Is this a DB call as well?
.Call System.Linq.Queryable.Take(
.Call System.Linq.Queryable.Where(
.Constant<Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[Employee.Models.EmployeeDetails]>(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[Employee.Models.EmployeeDetails]),
'(.Lambda #Lambda1<System.Func`2[Employee.Models.EmployeeDetails,System.Boolean]>)),
1).Lambda #Lambda1<System.Func`2[Employee.Models.EmployeeDetails,System.Boolean]>(Employee.Models.EmployeeDetails $x)
{
$x.Idseq == .Constant<TestProject.Program+<>c__DisplayClass2_0>(TestProject.Program+<>c__DisplayClass2_0).deptId
}
If this is the only DB call made among the two, then how come I am able to load the data for empDetails?
Question #2: now, I changed the type from IQueryable
to IEnumerable
.
My understanding here is DB call is made with where
clause and then loads the data in-memory and then takes the first element.
Is that true?
public void GetEmployeesByDept(long deptId)
{
IEnumerable<EmployeeDetails> empDetails = _context.EmployeeDetails.Where(x => x.Idseq == deptId);
// First DB call
var firstEmployee = empDetails.Take(1); // in-memory object
Console.WriteLine(empDetails.GetType());
}
Could anyone please correct me if my understanding is incorrect.
Thanks in advance
Upvotes: 1
Views: 591
Reputation: 26450
Check the Query execution documentation
After a LINQ query is created by a user, it is converted to a command tree. A command tree is a representation of a query that is compatible with the Entity Framework. The command tree is then executed against the data source. At query execution time, all query expressions (that is, all components of the query) are evaluated, including those expressions that are used in result materialization.
After a LINQ query is created by a user
You are creating the query in the lines below
IQueryable<EmployeeDetails> empDetails = _context.EmployeeDetails.Where(x => x.Idseq == deptId);
// first DB call
var firstEmployee = empDetails.Take(1);
LINQ queries are always executed when the query variable is iterated over, not when the query variable is created.
So only one call is made, when you access the firstEmployee variable.
IQueryable is also IEnumerable. So this line:
IEnumerable<EmployeeDetails> empDetails = _context.EmployeeDetails.Where(x => x.Idseq ==deptId);
Is not casting to IEnumerable. The empDetails
remains IQueryable
and will be executed again, when you access the firstEmployee
variable.
Is is optimised by executing the query, only when it is needed.
Upvotes: 2