Skip to main content

DbContext & Configuration

Level: Beginner

ℹ️ Where This Fits

DbContext is your entry point to EF Core. Configuring it properly ensures correct database connections, lazy loading behavior, and query performance. Master this before writing queries.

ℹ️ What You'll Learn
  • DbContext purpose: Bridge between C# code and database, contains DbSet properties for entities
  • DbSet definition: public DbSet<Student> Students { get; set; } represents database table
  • OnConfiguring method: Configure connection string, logging, lazy loading
  • UseSqlServer: Database provider for SQL Server (options.UseSqlServer(connString))
  • Logging configuration: Enable SQL query logging for debugging
  • Lazy loading: Automatic loading of related data when accessed (can cause N+1 queries)
  • ProxyCreationEnabled: Required for lazy loading (creates proxy classes)
  • Connection string: Store in appsettings.json, inject via IConfiguration
  • Dependency injection: Register DbContext in Program.cs (services.AddDbContext<SmsDbContext>())
  • DbContextOptions: Immutable configuration passed to DbContext constructor
  • Multiple databases: One DbContext per database typically
  • SaveChangesAsync: Async version of SaveChanges (preferred in modern apps)
  • ChangeTracker: Tracks entity modifications (enable/disable as needed)
  • School Management entities: Student, Teacher, Exam, ExamResult, Fee, Attendance
  • Common mistakes: Hardcoding connection string, creating DbContext without DI, not disposing context

OnConfiguring Setup

using Microsoft.EntityFrameworkCore;

public class SmsDbContext : DbContext
{
// Entity sets
public DbSet<Student> Students { get; set; }
public DbSet<Teacher> Teachers { get; set; }
public DbSet<Exam> Exams { get; set; }
public DbSet<ExamResult> ExamResults { get; set; }
public DbSet<FeeAccount> FeeAccounts { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder options)
{
if (!options.IsConfigured)
{
options
.UseSqlServer("Server=localhost;Database=SmsDb;User Id=sa;Password=YourPassword;")
.LogTo(Console.WriteLine, LogLevel.Information) // Log SQL queries
.EnableSensitiveDataLogging(); // Log parameter values (development only)
}
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Configure relationships, constraints here
}
}

Dependency Injection Setup (Program.cs)

var builder = WebApplication.CreateBuilder(args);

// Register DbContext with DI
builder.Services.AddDbContext<SmsDbContext>(options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
)
);

var app = builder.Build();

appsettings.json Configuration

{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=SmsDb;User Id=sa;Password=YourPassword;Connection Timeout=30;Min Pool Size=5;Max Pool Size=100;"
}
}

Using DbContext in Controller

[ApiController]
[Route("api/students")]
public class StudentsController : ControllerBase
{
private readonly SmsDbContext _context;

public StudentsController(SmsDbContext context)
{
_context = context;
}

[HttpGet]
public async Task<ActionResult<List<Student>>> GetStudents()
{
var students = await _context.Students
.Where(s => s.Status == StudentStatus.Active)
.ToListAsync();

return Ok(students);
}

[HttpPost]
public async Task<ActionResult<Student>> CreateStudent([FromBody] CreateStudentRequest request)
{
var student = new Student
{
Name = request.Name,
ClassName = request.ClassName,
Status = StudentStatus.Active
};

_context.Students.Add(student);
await _context.SaveChangesAsync();

return CreatedAtAction(nameof(GetStudent), new { id = student.Id }, student);
}

[HttpGet("{id}")]
public async Task<ActionResult<Student>> GetStudent(int id)
{
var student = await _context.Students.FindAsync(id);

if (student == null)
return NotFound();

return Ok(student);
}
}

Enable Lazy Loading (Optional)

protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options
.UseSqlServer(connString)
.UseLazyLoadingProxies() // Enable lazy loading
.LogTo(Console.WriteLine);
}

Then access related data automatically:

var student = await _context.Students.FirstAsync();
var exams = student.Exams; // Lazy loads from database automatically

Logging Configuration

.LogTo(
Console.WriteLine,
new[] { DbLoggerCategory.Database.Command.Name },
LogLevel.Information
)

This logs only SQL commands to console in Development.

Best Practices

✓ Always inject DbContext via DI ✓ Store connection strings in configuration ✓ Use async methods (SaveChangesAsync, ToListAsync) ✓ Dispose DbContext (using statement or DI handles this) ✓ Use separate DbContext per request in web apps

💡 Connection String Security

Never hardcode connection strings. Always:

  1. Store in appsettings.json (dev)
  2. Use Azure Key Vault or Environment Variables (production)
  3. Never commit secrets to git
🤖Use AI to Learn Faster

Use ChatGPT, Claude, or Copilot to go deeper on DbContext & Configuration. Try these prompts:

  • "How do you configure DbContext with dependency injection?"
  • "Where should you store connection strings?"
  • "What's the difference between OnConfiguring and OnModelCreating?"
  • "How do you enable lazy loading in EF Core?"

💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.

Next Article

-> 03. Entities & Data Models

nexcoding.in