Data layer and SQL
From LINQ to SQL: how EF Core translates a query
Which part runs in the database, which in memory, and how to read the generated SQL.
Understand the concept
A LINQ query you write in EF Core does not run immediately; it accumulates as an expression tree. When a terminating operator such as ToListAsync, SingleAsync or CountAsync is called, EF Core translates the tree into SQL, adds parameters and sends it to the database. Where, OrderBy, Select and Take become SQL and run in the database.
Projecting with Select fetches only the needed columns. Loading whole entities and using a few fields in memory moves needless data over the network, which matters a lot for large text columns. DTOs created by projection are not tracked; this is the most efficient path for read endpoints.
If an untranslatable expression (for example your own C# method) is used inside Where, EF Core throws rather than silently pulling the query into memory and filtering there. To see the generated SQL use ToQueryString() or EF Core logging in development. Making a habit of reading the SQL catches performance problems before production.
Two LINQ queries with the same result can produce very different SQL and cost.
Calling ToList() early and doing filtering and paging in memory.
A letter’s journey through the city
Think of a request as a letter and the server as a city. Pick a scenario, press play and watch which gates the letter passes and where it gets stopped.
You clicked a post. The browser writes a letter saying ‘send me this post’.
One topic. Three levels of depth.
var titles = await db.Posts
.Where(p => p.IsPublished)
.OrderByDescending(p => p.PublishedAtUtc)
.Select(p => p.Title)
.Take(5)
.ToListAsync(ct);
// SELECT TOP(@p) [p].[Title] FROM [Posts] AS [p]
// WHERE [p].[IsPublished] = 1 ORDER BY [p].[PublishedAtUtc] DESCThe whole chain becomes one SQL query that runs in the database.
This page connects to no real server or database. Code samples are illustrative for .NET 8, Next.js and SQL Server; timings are example values in the simulation, not measurements. Try samples only in your own development environment; never share real connection strings, tokens or passwords.
Try it yourself first.
The list page shows only title and date, but the query also loads the Content column (about 40 KB on average). How much needless data moves for a 20-post page, and how do you fix it?
Show the solution and explanation
≈ 20 × 40 KB = 800 KB gereksiz veri (her sayfa açılışında).
Düzeltme: .Select(p => new PostListItem(p.Title, p.PublishedAtUtc))Projection narrows the SQL SELECT list; database, network and memory load drop together.