Entity Framework Basics
Entity Framework Core (EF Core) is the ORM most ASP.NET apps use to talk to a database — you work with C# classes and LINQ queries, and EF Core translates that into SQL behind the scenes.
Defining a DbContext
A DbContext subclass represents a database session, with one DbSet<T> property per table you want to work with:
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Product> Products => Set<Product>();
}
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlite("Data Source=app.db"));
AddDbContext registers the context with ASP.NET's built-in dependency injection — any controller that asks for an AppDbContext in its constructor gets one, correctly scoped to that single request.
Creating the database with migrations
dotnet ef migrations add InitialCreate dotnet ef database update
Build started... Build succeeded. Done. To undo this action, use 'ef migrations remove' Applying migration '20260909000000_InitialCreate'. Done.
A migration is a generated file describing the schema change needed to go from the database's current state to match your DbContext — database update actually applies it, creating the Products table.
Querying with LINQ
private readonly AppDbContext _db;
public ProductsController(AppDbContext db) => _db = db;
[HttpGet]
public IActionResult GetExpensive()
{
var expensive = _db.Products
.Where(p => p.Price > 25)
.OrderBy(p => p.Name)
.ToList();
return Ok(expensive);
}
$ curl http://localhost:5225/api/products
[{"id":3,"name":"Monitor","price":179.99},{"id":1,"name":"Webcam","price":39.99}]_db.Products.Where(...).OrderBy(...) reads like an in-memory LINQ query over a list, but EF Core translates the whole chain into a single SQL SELECT ... WHERE ... ORDER BY statement — the filtering and sorting happen in the database, not in your app's memory.
DbContext is not thread-safe and is meant to be short-lived — one per request is exactly what AddDbContext's default "scoped" lifetime gives you. Holding onto a context across requests, or sharing one across concurrent operations, is a common source of hard-to-diagnose bugs and exceptions in real ASP.NET apps.