[{"data":1,"prerenderedAt":110},["ShallowReactive",2],{"qa-\u002Fdotnet\u002Fentity-framework\u002Fquerying":3},{"page":4,"siblings":94,"blog":107},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":6,"topic":90,"topicSlug":91,"updated":92,"__hash__":93},"qa\u002Fdotnet\u002Fentity-framework\u002Fquerying.md","Querying",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md",".NET Core","dotnet",{},true,3,"\u002Fdotnet\u002Fentity-framework\u002Fquerying",[23,28,32,36,40,44,48,52,56,61,65,69,73,77,81],{"id":24,"difficulty":25,"q":26,"a":27},"ef-iqueryable-vs-ienumerable","easy","What is the difference between IQueryable and IEnumerable in EF Core queries?","**`IQueryable\u003CT>`** builds an expression tree that EF Core translates to SQL —\nfiltering happens in the database. **`IEnumerable\u003CT>`** operates in memory —\nthe full result set is loaded first, then filtered in C#.\n\n```csharp\n\u002F\u002F IQueryable — WHERE clause runs on the DB:\nIQueryable\u003COrder> query = _db.Orders          \u002F\u002F still IQueryable — no SQL yet\n    .Where(o => o.CustomerId == customerId)    \u002F\u002F added to SQL: WHERE CustomerId = @p0\n    .Where(o => o.Total > 100);               \u002F\u002F added to SQL: AND Total > @p1\n\n\u002F\u002F Materialise — this is when SQL executes:\nvar orders = await query.ToListAsync();       \u002F\u002F SELECT ... WHERE CustomerId=? AND Total>?\n\n\u002F\u002F IEnumerable — loads ALL rows, then filters in memory:\nIEnumerable\u003COrder> allOrders = _db.Orders.AsEnumerable(); \u002F\u002F SELECT * FROM Orders (all rows!)\nvar expensive = allOrders.Where(o => o.Total > 100);      \u002F\u002F filtered in C# — too late\n\n\u002F\u002F Practical consequence:\npublic IQueryable\u003COrder> GetOrdersByCustomer(int id)\n    => _db.Orders.Where(o => o.CustomerId == id); \u002F\u002F callers can compose further SQL\n\npublic IEnumerable\u003COrder> GetOrdersByCustomerBad(int id)\n    => _db.Orders.Where(o => o.CustomerId == id).ToList(); \u002F\u002F materialised — composition lost\n```\n\n**Rule of thumb:** Keep queries as `IQueryable\u003CT>` until the last moment. Never call\n`.AsEnumerable()` or `.ToList()` mid-chain unless you intentionally want in-memory\nprocessing of a small set.\n",{"id":29,"difficulty":25,"q":30,"a":31},"ef-deferred-execution","What is deferred execution in EF Core and which operations trigger SQL?","EF Core queries are **deferred** — they build an expression tree but don't hit the\ndatabase until a **terminal operator** materialises the results.\n\n```csharp\n\u002F\u002F Building the query — NO SQL yet:\nvar query = _db.Orders\n    .Where(o => o.Status == \"Pending\")\n    .OrderBy(o => o.CreatedAt)\n    .Take(50);\n\n\u002F\u002F Terminal operators — each generates and executes SQL:\nvar list   = await query.ToListAsync();            \u002F\u002F SELECT ... (returns List\u003COrder>)\nvar first  = await query.FirstOrDefaultAsync();    \u002F\u002F SELECT TOP 1 ...\nvar count  = await query.CountAsync();             \u002F\u002F SELECT COUNT(*)\nvar any    = await query.AnyAsync();               \u002F\u002F SELECT CASE WHEN EXISTS(...)\nvar single = await query.SingleAsync();            \u002F\u002F SELECT ... (throws if 0 or 2+)\nvar array  = await query.ToArrayAsync();\nvar dict   = await query.ToDictionaryAsync(o => o.Id);\n\n\u002F\u002F foreach also triggers execution (but prefer ToListAsync for async):\nawait foreach (var order in query.AsAsyncEnumerable()) \u002F\u002F streaming — no full buffer\n    Process(order);\n\n\u002F\u002F Common mistake — calling the DB twice:\nvar q = _db.Products.Where(p => p.IsActive);\nvar count    = await q.CountAsync();  \u002F\u002F SELECT COUNT(*) — first trip\nvar products = await q.ToListAsync(); \u002F\u002F SELECT * — second trip\n\u002F\u002F Fix: do both in one query or materialise once.\n```\n\n**Rule of thumb:** A LINQ chain on `DbSet\u003CT>` is just a description. SQL executes\nonly at `ToListAsync`, `FirstOrDefaultAsync`, `CountAsync`, `AnyAsync`, etc.\nAvoid materialising the same query twice.\n",{"id":33,"difficulty":25,"q":34,"a":35},"ef-projection","How do you use projections (Select) to load only the columns you need?","**Projection** via `.Select()` instructs EF Core to generate a `SELECT` with only\nthe specified columns, reducing data transfer and avoiding unnecessary object overhead.\n\n```csharp\n\u002F\u002F Loads all columns including large blobs:\nvar orders = await _db.Orders\n    .Where(o => o.CustomerId == customerId)\n    .ToListAsync(); \u002F\u002F SELECT Id, CustomerId, Status, Total, Notes, Blob, ...\n\n\u002F\u002F Project to a DTO — only fetches needed columns:\nvar summaries = await _db.Orders\n    .Where(o => o.CustomerId == customerId)\n    .Select(o => new OrderSummaryDto\n    {\n        Id     = o.Id,\n        Status = o.Status,\n        Total  = o.Total\n    })\n    .ToListAsync(); \u002F\u002F SELECT Id, Status, Total FROM Orders WHERE CustomerId = @p0\n\n\u002F\u002F Anonymous type projection (quick\u002Flocal use):\nvar ids = await _db.Orders\n    .Where(o => o.Status == \"Pending\")\n    .Select(o => new { o.Id, o.CreatedAt })\n    .ToListAsync();\n\n\u002F\u002F Nested projection — joins happen in one query:\nvar result = await _db.Orders\n    .Select(o => new OrderDetailDto\n    {\n        Id           = o.Id,\n        CustomerName = o.Customer.Name,  \u002F\u002F JOIN generated automatically\n        Items        = o.Items.Select(i => new ItemDto\n        {\n            ProductName = i.Product.Name,\n            Quantity    = i.Quantity\n        }).ToList()\n    })\n    .ToListAsync();\n```\n\n**Rule of thumb:** Always project to a DTO or anonymous type when the query result\nis read-only. Loading full entities just to read two columns wastes bandwidth and\nmemory, especially for large tables.\n",{"id":37,"difficulty":14,"q":38,"a":39},"ef-eager-loading","What is eager loading and how do you use Include and ThenInclude?","**Eager loading** fetches related entities in the same query via SQL `JOIN` using\n`Include` and `ThenInclude`, avoiding separate round trips to the database.\n\n```csharp\n\u002F\u002F Without Include — navigation properties are null:\nvar order = await _db.Orders.FindAsync(42);\nConsole.WriteLine(order.Customer.Name); \u002F\u002F NullReferenceException — not loaded\n\n\u002F\u002F Include — adds a JOIN for the related table:\nvar order = await _db.Orders\n    .Include(o => o.Customer)                  \u002F\u002F JOIN Customers\n    .Include(o => o.Items)                     \u002F\u002F JOIN OrderItems\n    .FirstOrDefaultAsync(o => o.Id == 42);\n\n\u002F\u002F ThenInclude — navigate deeper into the graph:\nvar orders = await _db.Orders\n    .Include(o => o.Items)                     \u002F\u002F JOIN OrderItems\n        .ThenInclude(i => i.Product)           \u002F\u002F JOIN Products\n    .Include(o => o.Customer)\n        .ThenInclude(c => c.Address)           \u002F\u002F JOIN Addresses\n    .Where(o => o.Status == \"Pending\")\n    .ToListAsync();\n\n\u002F\u002F Filtered include (EF Core 5+) — only include a subset of related items:\nvar orders = await _db.Orders\n    .Include(o => o.Items.Where(i => !i.IsCancelled))\n    .ToListAsync();\n\n\u002F\u002F Include with AsNoTracking for read-only operations:\nvar orders = await _db.Orders\n    .AsNoTracking()\n    .Include(o => o.Items)\n    .ToListAsync();\n```\n\n**Rule of thumb:** Use `Include` for 1–2 levels of related data when you know you'll\nneed it. Deep or conditional includes can generate complex SQL — consider splitting\ninto multiple queries for very deep graphs.\n",{"id":41,"difficulty":14,"q":42,"a":43},"ef-n-plus-one","What is the N+1 query problem and how do you fix it in EF Core?","The **N+1 problem** occurs when code issues one query to load N parents, then N\nadditional queries — one per parent — to load a related collection. Total: N+1 queries.\n\n```csharp\n\u002F\u002F N+1 — lazy loading or iterating without Include:\nvar customers = await _db.Customers.ToListAsync(); \u002F\u002F Query 1: SELECT * FROM Customers\n\nforeach (var customer in customers)\n{\n    \u002F\u002F Query 2..N+1: SELECT * FROM Orders WHERE CustomerId = @id (once per customer!)\n    var count = customer.Orders.Count;\n    Console.WriteLine($\"{customer.Name}: {count} orders\");\n}\n\u002F\u002F 100 customers = 101 queries\n\n\u002F\u002F Fix 1 — eager load with Include:\nvar customers = await _db.Customers\n    .Include(c => c.Orders)\n    .ToListAsync(); \u002F\u002F 1 query with JOIN\n\n\u002F\u002F Fix 2 — project the count into the initial query:\nvar summary = await _db.Customers\n    .Select(c => new\n    {\n        c.Name,\n        OrderCount = c.Orders.Count  \u002F\u002F COUNT(*) in a subquery — 1 SQL statement\n    })\n    .ToListAsync();\n\n\u002F\u002F Fix 3 — split query (EF Core 5+) for very wide result sets:\nvar customers = await _db.Customers\n    .Include(c => c.Orders)\n    .AsSplitQuery()   \u002F\u002F 2 queries: one for Customers, one for Orders (no cartesian)\n    .ToListAsync();\n\n\u002F\u002F Detect N+1 in development with EF Core logging:\noptions.LogTo(Console.WriteLine, LogLevel.Information);\n\u002F\u002F or use MiniProfiler, EF Core interceptors, or Application Insights\n```\n\n**Rule of thumb:** Never loop over a collection and access a navigation property\ninside the loop without first loading it via `Include`. Enable query logging in\ndevelopment to catch N+1 patterns before they reach production.\n",{"id":45,"difficulty":14,"q":46,"a":47},"ef-lazy-loading","What is lazy loading in EF Core and why is it dangerous in web applications?","**Lazy loading** automatically loads navigation properties the first time they are\naccessed by issuing an additional query — convenient but dangerous in web APIs\nbecause it hides N+1 queries.\n\n```csharp\n\u002F\u002F Enable lazy loading via proxies:\n\u002F\u002F Install: dotnet add package Microsoft.EntityFrameworkCore.Proxies\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options\n        .UseSqlServer(connectionString)\n        .UseLazyLoadingProxies()); \u002F\u002F wraps entities in dynamic proxies\n\n\u002F\u002F Navigation properties must be virtual:\npublic class Order\n{\n    public int Id { get; set; }\n    public virtual Customer Customer { get; set; } \u002F\u002F loaded lazily on first access\n    public virtual ICollection\u003COrderItem> Items { get; set; } \u002F\u002F same\n}\n\n\u002F\u002F Lazy loading in a controller — silent N+1:\nvar orders = await _db.Orders.ToListAsync(); \u002F\u002F 1 query\nforeach (var o in orders)\n    Console.WriteLine(o.Customer.Name); \u002F\u002F +1 query PER ORDER — hidden!\n\n\u002F\u002F Lazy loading after DbContext is disposed:\nOrder GetOrder()\n{\n    using var db = new AppDbContext(opts);\n    return db.Orders.Find(1);\n} \u002F\u002F context disposed here\nvar order = GetOrder();\nConsole.WriteLine(order.Customer.Name); \u002F\u002F ObjectDisposedException\n\n\u002F\u002F Prefer explicit eager loading or projections:\nvar orders = await _db.Orders.Include(o => o.Customer).ToListAsync();\n```\n\n**Rule of thumb:** Disable lazy loading in web APIs. Use explicit `Include` or\nprojections so every query is visible and intentional. Lazy loading belongs only in\ndesktop or interactive applications where the context lives long enough.\n",{"id":49,"difficulty":14,"q":50,"a":51},"ef-raw-sql","When and how do you execute raw SQL in EF Core?","EF Core provides raw SQL APIs for queries that LINQ can't express — full-text search,\nstored procedures, database-specific functions, and bulk operations.\n\n```csharp\n\u002F\u002F FromSqlRaw — raw SQL that returns entity rows (can compose LINQ on top):\nvar orders = await _db.Orders\n    .FromSqlRaw(\"SELECT * FROM Orders WHERE Status = {0}\", \"Pending\")\n    .Where(o => o.Total > 100)    \u002F\u002F LINQ composed on top of the raw SQL\n    .OrderBy(o => o.CreatedAt)\n    .ToListAsync();\n\n\u002F\u002F FromSqlInterpolated — safer, uses parameterized queries automatically:\nstring status = \"Pending\";\nvar orders = await _db.Orders\n    .FromSqlInterpolated($\"SELECT * FROM Orders WHERE Status = {status}\")\n    .ToListAsync();\n\n\u002F\u002F ExecuteSqlRawAsync — non-query statements (no entity return):\nint rows = await _db.Database.ExecuteSqlRawAsync(\n    \"DELETE FROM Orders WHERE CreatedAt \u003C {0} AND Status = {1}\",\n    cutoff, \"Cancelled\");\n\n\u002F\u002F ExecuteSqlInterpolatedAsync — same but parameterized via interpolation:\nawait _db.Database.ExecuteSqlInterpolatedAsync(\n    $\"UPDATE Products SET Stock = Stock - {quantity} WHERE Id = {productId}\");\n\n\u002F\u002F Calling a stored procedure that returns entities:\nvar results = await _db.Orders\n    .FromSqlRaw(\"EXEC sp_GetPendingOrders @CustomerId = {0}\", customerId)\n    .ToListAsync();\n\n\u002F\u002F SQL injection risk — NEVER string-concatenate user input:\nstring unsafe = $\"SELECT * FROM Orders WHERE Status = '{userInput}'\"; \u002F\u002F vulnerable!\n\u002F\u002F Always use parameterized overloads.\n```\n\n**Rule of thumb:** Use parameterized `FromSqlInterpolated` and\n`ExecuteSqlInterpolatedAsync` — not `Raw` variants — whenever the SQL includes any\nuser-provided values. EF Core's interpolation converts `{variable}` to DB parameters\nautomatically.\n",{"id":53,"difficulty":25,"q":54,"a":55},"ef-async-queries","Why should EF Core queries always use async methods like ToListAsync?","**Async EF Core queries** (`ToListAsync`, `FirstOrDefaultAsync`, etc.) release the\nthread to the thread pool while waiting for the database, improving throughput under\nconcurrent load.\n\n```csharp\n\u002F\u002F Async — thread released to pool while DB executes:\nvar orders = await _db.Orders\n    .Where(o => o.Status == \"Pending\")\n    .ToListAsync(cancellationToken); \u002F\u002F thread free during DB wait\n\n\u002F\u002F Sync — thread blocks for the entire DB round trip:\nvar orders = _db.Orders\n    .Where(o => o.Status == \"Pending\")\n    .ToList(); \u002F\u002F thread occupied — in ASP.NET Core this wastes a thread pool slot\n\n\u002F\u002F .Result \u002F .Wait() — causes deadlocks in ASP.NET Core:\nvar orders = _db.Orders.ToListAsync().Result; \u002F\u002F potential deadlock\n\n\u002F\u002F Use CancellationToken throughout:\npublic async Task\u003CList\u003COrder>> GetPendingAsync(CancellationToken ct)\n    => await _db.Orders\n        .Where(o => o.Status == \"Pending\")\n        .AsNoTracking()\n        .ToListAsync(ct); \u002F\u002F honours request cancellation (client disconnect)\n\n\u002F\u002F Stream large result sets with AsAsyncEnumerable:\nawait foreach (var order in _db.Orders.AsAsyncEnumerable())\n{\n    await ProcessAsync(order); \u002F\u002F process one at a time — no full buffer in memory\n}\n```\n\n**Rule of thumb:** Always use `*Async` EF Core methods in ASP.NET Core and pass the\n`CancellationToken` from the action or endpoint. Sync calls waste thread pool threads\nand block under load.\n",{"id":57,"difficulty":58,"q":59,"a":60},"ef-compiled-queries","hard","What are compiled queries in EF Core and when do they give a measurable speedup?","**Compiled queries** (`EF.CompileAsyncQuery`) pre-compile the LINQ expression to SQL\nonce at startup and cache the result, skipping query translation on every call.\nUseful for hot paths called thousands of times per second.\n\n```csharp\n\u002F\u002F Standard query — translates LINQ to SQL on every call:\npublic async Task\u003COrder?> GetOrderAsync(int id)\n    => await _db.Orders.FirstOrDefaultAsync(o => o.Id == id);\n\u002F\u002F EF Core caches most queries internally, but compilation still has overhead.\n\n\u002F\u002F Compiled query — translation happens once at class initialisation:\nprivate static readonly Func\u003CAppDbContext, int, Task\u003COrder?>> GetOrderById =\n    EF.CompileAsyncQuery(\n        (AppDbContext db, int id) =>\n            db.Orders.FirstOrDefault(o => o.Id == id));\n\n\u002F\u002F Usage — no translation overhead:\nvar order = await GetOrderById(_db, id);\n\n\u002F\u002F With a collection parameter:\nprivate static readonly Func\u003CAppDbContext, IEnumerable\u003Cint>, IAsyncEnumerable\u003COrder>> GetOrdersByIds =\n    EF.CompileAsyncQuery(\n        (AppDbContext db, IEnumerable\u003Cint> ids) =>\n            db.Orders.Where(o => ids.Contains(o.Id)));\n\nawait foreach (var order in GetOrdersByIds(_db, new[] { 1, 2, 3 }))\n    Process(order);\n```\n\nWhen to use compiled queries:\n- Hot paths: endpoint called 1,000+ times\u002Fsecond where query planning overhead is measurable.\n- The query shape is fixed — no dynamic `Where` conditions or `Include` changes.\n- Profiling confirms EF's internal cache isn't enough.\n\n**Rule of thumb:** Don't reach for compiled queries prematurely. EF Core caches most\nqueries internally. Compiled queries pay off only on very hot, fixed-shape paths;\nmeasure first.\n",{"id":62,"difficulty":14,"q":63,"a":64},"ef-split-queries","What are split queries in EF Core and when should you use them?","**Split queries** (`AsSplitQuery`) execute a single LINQ query as multiple SQL queries\nrather than one query with multiple JOINs, avoiding the **Cartesian explosion** that\noccurs when including multiple collections.\n\n```csharp\n\u002F\u002F Single query with multiple collection includes — Cartesian explosion:\n\u002F\u002F Orders × Items × Tags → each combination is a row; rows multiply rapidly\nvar orders = await _db.Orders\n    .Include(o => o.Items)   \u002F\u002F 10 items each\n    .Include(o => o.Tags)    \u002F\u002F 5 tags each\n    .ToListAsync();\n\u002F\u002F Generates: SELECT ... FROM Orders JOIN OrderItems JOIN Tags\n\u002F\u002F 100 orders × 10 items × 5 tags = 5,000 rows transferred\n\n\u002F\u002F Split query — 3 separate SQL statements:\nvar orders = await _db.Orders\n    .Include(o => o.Items)\n    .Include(o => o.Tags)\n    .AsSplitQuery()          \u002F\u002F 3 SQL queries: Orders, Items, Tags\n    .ToListAsync();\n\u002F\u002F Each table queried once; no Cartesian product\n\n\u002F\u002F Set split query as the global default:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString,\n        sql => sql.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)));\n\n\u002F\u002F Override back to single query when needed:\nvar orders = await _db.Orders\n    .Include(o => o.Customer)    \u002F\u002F just one navigation — no explosion\n    .AsSingleQuery()\n    .ToListAsync();\n```\n\nTrade-offs of split queries:\n- **Pro:** avoids Cartesian explosion for multiple collection includes.\n- **Con:** multiple round trips — inconsistent if data changes between them.\n- **Con:** no transaction by default — wrap in one if consistency matters.\n\n**Rule of thumb:** Use `AsSplitQuery` when including two or more collections on the\nsame entity. Use single query when including only reference navigations or one collection.\n",{"id":66,"difficulty":14,"q":67,"a":68},"ef-groupby-aggregations","How does EF Core translate GroupBy and aggregate functions to SQL?","EF Core translates `GroupBy` with aggregate functions (`Count`, `Sum`, `Average`,\n`Min`, `Max`) directly to `GROUP BY` SQL. Without aggregation, it falls back to\nclient-side grouping after loading all rows — a common performance trap.\n\n```csharp\n\u002F\u002F GroupBy + aggregate — translated to SQL GROUP BY:\nvar ordersByStatus = await _db.Orders\n    .GroupBy(o => o.Status)\n    .Select(g => new\n    {\n        Status = g.Key,\n        Count  = g.Count(),\n        Total  = g.Sum(o => o.Total)\n    })\n    .ToListAsync();\n\u002F\u002F SQL: SELECT Status, COUNT(*), SUM(Total) FROM Orders GROUP BY Status\n\n\u002F\u002F Multiple keys:\nvar byCustomerAndMonth = await _db.Orders\n    .GroupBy(o => new { o.CustomerId, Month = o.CreatedAt.Month })\n    .Select(g => new\n    {\n        g.Key.CustomerId,\n        g.Key.Month,\n        Count = g.Count(),\n        Revenue = g.Sum(o => o.Total)\n    })\n    .ToListAsync();\n\u002F\u002F SQL: GROUP BY CustomerId, MONTH(CreatedAt)\n\n\u002F\u002F GroupBy without aggregate — EF falls back to client evaluation:\nvar groups = await _db.Orders\n    .GroupBy(o => o.Status)\n    .ToListAsync(); \u002F\u002F SELECT * FROM Orders — loads ALL rows, groups in memory\n\u002F\u002F In EF Core 3+, this throws or warns. Always project to aggregates.\n\n\u002F\u002F HAVING clause — filter groups by aggregate:\nvar activeCustomers = await _db.Orders\n    .GroupBy(o => o.CustomerId)\n    .Where(g => g.Count() >= 5)     \u002F\u002F translated to HAVING COUNT(*) >= 5\n    .Select(g => new { CustomerId = g.Key, OrderCount = g.Count() })\n    .ToListAsync();\n```\n\n**Rule of thumb:** Always combine `GroupBy` with at least one aggregate function\n(`Count`, `Sum`, etc.) in the `Select`. Without it, EF Core 3+ either throws or\nloads the entire table into memory.\n",{"id":70,"difficulty":25,"q":71,"a":72},"ef-no-tracking","What is AsNoTracking and when should you use it?","**`AsNoTracking()`** instructs EF Core to skip change tracking for a query's results.\nThe returned entities are disconnected from the context — changes to them are not\ndetected by `SaveChanges`.\n\n```csharp\n\u002F\u002F Default (tracked) — entities registered with the change tracker:\nvar order = await _db.Orders.FindAsync(42);\norder.Status = \"Shipped\";\nawait _db.SaveChangesAsync(); \u002F\u002F detects change, generates UPDATE\n\n\u002F\u002F AsNoTracking — entities are plain C# objects, no change tracker registration:\nvar orders = await _db.Orders\n    .AsNoTracking()\n    .Where(o => o.Status == \"Pending\")\n    .ToListAsync();\n\u002F\u002F Faster: no identity map lookup, no snapshot copy, lower memory\n\n\u002F\u002F AsNoTrackingWithIdentityResolution (EF Core 5+) — no tracking BUT\n\u002F\u002F returns the same object instance for the same PK within the query:\nvar orders = await _db.Orders\n    .AsNoTrackingWithIdentityResolution()\n    .Include(o => o.Customer)\n    .ToListAsync();\n\u002F\u002F Multiple orders sharing the same customer → same Customer object in memory\n\n\u002F\u002F Global default for a context (read-heavy reporting context):\npublic class ReportDbContext : DbContext\n{\n    protected override void OnConfiguring(DbContextOptionsBuilder b)\n        => b.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);\n}\n```\n\nBenchmarks typically show **10–20% faster query materialisation** and **lower GC\npressure** with `AsNoTracking` on large result sets.\n\n**Rule of thumb:** Add `AsNoTracking()` to every query in a read-only path (API\nGET endpoints, reports, search). Only track entities you plan to modify and save.\n",{"id":74,"difficulty":25,"q":75,"a":76},"ef-pagination","How do you implement pagination with EF Core?","**Pagination** in EF Core is achieved with `.Skip()` and `.Take()` which translate\nto `OFFSET` \u002F `FETCH NEXT` (or equivalent) in SQL. Always combine with `OrderBy`\nso results are deterministic.\n\n```csharp\n\u002F\u002F Offset-based pagination — page 1 = skip 0, page 2 = skip pageSize, etc.:\npublic async Task\u003CPagedResult\u003COrderSummaryDto>> GetOrdersAsync(int page, int pageSize)\n{\n    var query = _db.Orders\n        .AsNoTracking()\n        .Where(o => o.Status == \"Pending\")\n        .OrderByDescending(o => o.CreatedAt); \u002F\u002F required — results are non-deterministic without it\n\n    var total = await query.CountAsync(); \u002F\u002F SELECT COUNT(*) — same filter\n\n    var items = await query\n        .Skip((page - 1) * pageSize) \u002F\u002F OFFSET\n        .Take(pageSize)              \u002F\u002F FETCH NEXT\n        .Select(o => new OrderSummaryDto\n        {\n            Id     = o.Id,\n            Status = o.Status,\n            Total  = o.Total\n        })\n        .ToListAsync();\n\n    return new PagedResult\u003COrderSummaryDto>(items, total, page, pageSize);\n}\n\u002F\u002F SQL: SELECT Id, Status, Total FROM Orders WHERE Status='Pending'\n\u002F\u002F      ORDER BY CreatedAt DESC OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY\n\n\u002F\u002F Keyset (cursor) pagination — faster for large offsets:\n\u002F\u002F Instead of SKIP, filter by the last seen value:\nvar items = await _db.Orders\n    .AsNoTracking()\n    .Where(o => o.CreatedAt \u003C lastSeenCreatedAt) \u002F\u002F cursor\n    .OrderByDescending(o => o.CreatedAt)\n    .Take(pageSize)\n    .ToListAsync();\n\u002F\u002F No OFFSET scan — index seek directly to the cursor position\n```\n\n**Rule of thumb:** Use offset pagination for small datasets where any page can be\njumped to. Use keyset (cursor) pagination for large tables or infinite scroll — it\nscales to millions of rows without degrading as the page number grows.\n",{"id":78,"difficulty":25,"q":79,"a":80},"ef-like-contains-search","How do you perform text search (LIKE, full-text) with EF Core?","EF Core translates `.Contains()`, `.StartsWith()`, and `.EndsWith()` to SQL `LIKE`\npatterns. For full-text search, use `EF.Functions.Like` or database-specific functions.\n\n```csharp\n\u002F\u002F Contains → LIKE '%value%' (substring search — can't use an index efficiently):\nvar results = await _db.Products\n    .AsNoTracking()\n    .Where(p => p.Name.Contains(\"widget\"))\n    .ToListAsync();\n\u002F\u002F SQL: WHERE Name LIKE '%widget%'\n\n\u002F\u002F StartsWith → LIKE 'value%' (prefix — can use a B-tree index):\nvar results = await _db.Products\n    .Where(p => p.Sku.StartsWith(\"WGT-\"))\n    .ToListAsync();\n\u002F\u002F SQL: WHERE Sku LIKE 'WGT-%'\n\n\u002F\u002F EF.Functions.Like — more control over the pattern:\nvar results = await _db.Products\n    .Where(p => EF.Functions.Like(p.Name, \"%wid_et%\")) \u002F\u002F _ matches one character\n    .ToListAsync();\n\n\u002F\u002F Case-insensitive comparison (depends on DB collation; explicit on SQLite):\nvar results = await _db.Products\n    .Where(p => EF.Functions.Like(p.Name, \"%widget%\")) \u002F\u002F case-insensitive on SQL Server default collation\n\n\u002F\u002F SQL Server full-text search (requires FTS index on the column):\nvar results = await _db.Products\n    .Where(p => EF.Functions.Contains(p.Description, \"widget OR gadget\"))\n    .ToListAsync();\n\u002F\u002F SQL: WHERE CONTAINS(Description, 'widget OR gadget')\n\n\u002F\u002F Warning: never pass unvalidated user input directly into EF.Functions.Like —\n\u002F\u002F the pattern itself is parameterized, but wildcard injection is still possible:\nstring safe = $\"%{userInput.Replace(\"%\", \"[%]\").Replace(\"_\", \"[_]\")}%\";\n```\n\n**Rule of thumb:** Use `StartsWith` for prefix search on indexed columns. Use\n`Contains` sparingly — `LIKE '%value%'` causes full table scans. Use database\nfull-text search (`EF.Functions.Contains`) for production text search requirements.\n",{"id":82,"difficulty":14,"q":83,"a":84},"ef-explicit-loading","What is explicit loading in EF Core and how does it differ from eager and lazy loading?","**Explicit loading** loads a navigation property on demand after the entity is already\nin memory — using `LoadAsync` on the entry's reference or collection. Unlike lazy loading\nit is intentional and visible in code; unlike eager loading it's a separate SQL round trip.\n\n```csharp\n\u002F\u002F Load the entity first (navigation not included):\nvar order = await _db.Orders.FindAsync(42); \u002F\u002F SELECT * FROM Orders WHERE Id=42\n\n\u002F\u002F Explicit load — second query, triggered intentionally:\nawait _db.Entry(order)\n         .Reference(o => o.Customer)  \u002F\u002F reference navigation (single entity)\n         .LoadAsync();\n\u002F\u002F SQL: SELECT * FROM Customers WHERE Id = @customerId\n\nawait _db.Entry(order)\n         .Collection(o => o.Items)    \u002F\u002F collection navigation\n         .LoadAsync();\n\u002F\u002F SQL: SELECT * FROM OrderItems WHERE OrderId = 42\n\n\u002F\u002F Filter the collection while loading (EF Core 5+):\nawait _db.Entry(order)\n         .Collection(o => o.Items)\n         .Query()                                  \u002F\u002F IQueryable on the collection\n         .Where(i => !i.IsCancelled)\n         .LoadAsync();\n\u002F\u002F SQL: SELECT * FROM OrderItems WHERE OrderId=42 AND IsCancelled=0\n\n\u002F\u002F Comparison:\n\u002F\u002F Eager  (Include)   — one query with JOIN, loaded before you need it\n\u002F\u002F Lazy               — automatic, invisible, N+1 risk\n\u002F\u002F Explicit (LoadAsync) — extra query, but intentional and filterable\n\n\u002F\u002F Check before loading to avoid a redundant query:\nvar entry = _db.Entry(order);\nif (!entry.Collection(o => o.Items).IsLoaded)\n    await entry.Collection(o => o.Items).LoadAsync();\n```\n\n**Rule of thumb:** Use explicit loading when you don't know at query time whether\nyou'll need the related data — for example, conditional logic that only sometimes\nneeds the collection. For always-needed data, prefer `Include` to load everything\nin one round trip.\n",15,null,{"description":11},"EF Core querying interview questions — IQueryable vs IEnumerable, eager loading, the N+1 problem, projections, raw SQL, and compiled queries.","dotnet\u002Fentity-framework\u002Fquerying","Entity Framework Core","entity-framework","2026-06-23","Tvzik-2CyfM3KJu1hNE7UOaK6Lki1wBDLbXGqCzNxvc",[95,99,102,103],{"subtopic":96,"path":97,"order":98},"DbContext & DbSet","\u002Fdotnet\u002Fentity-framework\u002Fdbcontext-dbset",1,{"subtopic":100,"path":101,"order":12},"Migrations","\u002Fdotnet\u002Fentity-framework\u002Fmigrations",{"subtopic":6,"path":21,"order":20},{"subtopic":104,"path":105,"order":106},"Relationships","\u002Fdotnet\u002Fentity-framework\u002Frelationships",4,{"path":108,"title":109},"\u002Fblog\u002Fdotnet-ef-querying","How EF Core Translates LINQ to SQL",1782244118636]