Lesson 20 / 26
Querying and Saving Data
Read with LINQ, avoid the N+1 problem and write changes with SaveChangesAsync.
LINQ becomes SQL
EF Core translates Where and Select into SQL, so filtering happens in the database. Use AsNoTracking() for read-only queries to skip change tracking, and always use the Async methods in web apps.
CRUD endpoints
Read cheap books without tracking, and add a book then save once. Related data is loaded explicitly with Include.
app.MapGet("/books", async (ShopDb db) =>
await db.Books.AsNoTracking()
.Where(b => b.Price < 500)
.OrderBy(b => b.Title)
.ToListAsync());
app.MapPost("/books", async (Book b, ShopDb db) =>
{
db.Books.Add(b);
await db.SaveChangesAsync();
return Results.Created($"/books/{b.Id}", b);
});The N+1 trap
Looping over orders and touching each order's items can fire one query per order. Load related rows in a single query with Include, or project to a DTO with Select. Log SQL in development to notice this early.
Quick check: What does AsNoTracking() do?
- Deletes the rows
- Encrypts the query
- Disables caching of the table
- Skips change tracking for a faster read-only query
Answer
Skips change tracking for a faster read-only query — Returned entities are not tracked, which saves memory and time when you will not update them.