← Documentation index · Repository home
DbContext is a short-lived unit-of-work boundary. It translates LINQ, tracks selected entities, and coordinates a transaction when SaveChanges is called.
Note
This guidance is intentionally practical. Confirm version-sensitive behavior against current primary documentation.
In backend services, context lifetime and query shape affect correctness and capacity. A context shared across work items is neither thread-safe nor a reliable cache.
| # | Engineering principle |
|---|---|
| 1 | Tracked entities support change detection and updates. |
| 2 | No-tracking projections reduce work for read models. |
| 3 | SaveChanges groups pending changes in a transaction by default. |
An order query returns a purpose-built summary without loading the aggregate or tracking rows that will never be updated.
In a production service, I would define the boundary first, make ownership visible, add telemetry around the failure modes, and introduce the change in a reversible slice. The specific design should follow workload, data sensitivity, deployment constraints, and the maintenance cost for the team that owns it.
- Define expected failure behavior, timeout or transaction boundaries, and recovery.
- Make logs and traces useful without recording credentials or sensitive business data.
- Verify the design with representative concurrency and data volume.
flowchart LR
API["API request"] --> Service["Application service"]
Service --> Query["LINQ expression"]
Query --> EF["EF Core translator"]
EF --> SQL["Parameterized SQL"]
SQL --> DB["SQL Server"]
DB --> Materialize["Projection/materialization"]
Materialize --> API
var summary = await dbContext.Orders
.AsNoTracking()
.Where(order => order.Id == orderId)
.Select(order => new OrderSummary(order.Id, order.Status, order.Total))
.SingleOrDefaultAsync(cancellationToken);- Use one scoped context per request or explicit unit of work.
- Project only fields needed by the response.
- Inspect generated SQL for important queries.
- Returning IQueryable across architectural boundaries.
- Using Include to load an unbounded graph.
- Attaching request payloads and marking every property modified.
- When should AsNoTracking be used?
- Is DbContext thread-safe?
- How does SaveChanges handle transactions?
How to answer well
State the governing rule, use a concrete backend example, explain the main trade-off, and describe how you would verify the decision in production.