Entity Framework Migrations
Relevant source files
The following files were used as context for generating this wiki page:Entity Framework (EF) Core Migrations are used in the PeP5 project to manage the evolution of the application's database schema. As the data models defined in the PeP.Models namespace change, migrations provide a version-controlled, code-based way to update the database structure to match. This ensures that the database schema is always in sync with the application's entity classes.
The entire system is orchestrated through the ApplicationDbContext, which defines the set of entities to be managed and their relationships. Migrations are generated as C# classes, each representing a set of incremental changes. These migrations are automatically applied at application startup to ensure the database is up-to-date.
Core Components
ApplicationDbContext
The ApplicationDbContext class is the heart of the data access layer, inheriting from Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext<ApplicationUser>. It is responsible for defining the entities that make up the application's data model and configuring their relationships and constraints.
Sources: Data/ApplicationDbContext.cs:7-10
It contains DbSet<T> properties for every entity that needs to be persisted to the database. This includes core entities for standard exams and a comprehensive set for programming exams.
// Data/ApplicationDbContext.cs:12-34
public DbSet<Course> Courses { get; set; }
public DbSet<Exam> Exams { get; set; }
public DbSet<Question> Questions { get; set; }
// ... other standard exam DbSets
// Programming Exam entities
public DbSet<ProgrammingExam> ProgrammingExams { get; set; }
public DbSet<ProgrammingTask> ProgrammingTasks { get; set; }
public DbSet<TestCase> TestCases { get; set; }
public DbSet<ProjectFile> ProjectFiles { get; set; }
public DbSet<ProgrammingExamAttempt> ProgrammingExamAttempts { get; set; }
public DbSet<StudentProjectFile> StudentProjectFiles { get; set; }
public DbSet<TaskProgress> TaskProgresses { get; set; }
public DbSet<TestCaseResult> TestCaseResults { get; set; }
public DbSet<CodeSubmission> CodeSubmissions { get; set; }
public DbSet<ConsoleHistory> ConsoleHistories { get; set; }
public DbSet<ProgrammingExamCode> ProgrammingExamCodes { get; set; }
Sources: Data/ApplicationDbContext.cs:12-34
Model Configuration
The OnModelCreating method within ApplicationDbContext uses the ModelBuilder API to configure entity relationships, constraints, indexes, and data seeding. This fluent API provides a detailed, code-based definition of the database schema.
Key configurations include:
- Relationships: Defining foreign keys and navigation properties (e.g., an
Exambelongs to aCourse). - Delete Behaviors: Specifying cascade, restrict, or no action on delete operations. For example, deleting a
ProgrammingExamwill also delete its associatedTasksandStarterFiles(DeleteBehavior.Cascade), but not theApplicationUserwho created it (DeleteBehavior.Restrict). - Indexes: Creating database indexes to improve query performance, including unique indexes.
- Data Seeding: Populating the database with initial data, such as
PlatformSettingvalues.
The diagram below shows some of the key relationships for the Programming Exam feature as defined in OnModelCreating.
This ER diagram illustrates the relationships between the main entities of the programming exam module.
Sources: Data/ApplicationDbContext.cs:220-348, Models/ProgrammingExamModels.cs
Migration Classes
Each migration is a class that inherits from Microsoft.EntityFrameworkCore.Migrations.Migration. These classes are stored in the Migrations/ directory and are named with a timestamp followed by a descriptive title.
Each migration class contains two primary methods:
Up(MigrationBuilder migrationBuilder): This method defines the schema changes to be applied to the database. It uses themigrationBuilderAPI to create tables, add columns, create indexes, etc.Down(MigrationBuilder migrationBuilder): This method defines the actions to revert the changes made by theUpmethod. This is used if a migration needs to be rolled back.
Example: Adding New Tables
The AddProgrammingExams migration introduces all the tables required for the programming exam feature.
// Migrations/20251223122534_AddProgrammingExams.cs:9-35
public partial class AddProgrammingExams : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "ProgrammingExams",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Title = table.Column<string>(type: "nvarchar(300)", maxLength: 300, nullable: false),
// ... other columns
},
constraints: table =>
{
table.PrimaryKey("PK_ProgrammingExams", x => x.Id);
table.ForeignKey(
name: "FK_ProgrammingExams_AspNetUsers_CreatedByUserId",
// ...
);
table.ForeignKey(
name: "FK_ProgrammingExams_Courses_CourseId",
// ...
);
});
// ... calls to CreateTable for ProgrammingExamAttempts, ProgrammingTasks, etc.
}
// ... Down method
}
Sources: Migrations/20251223122534_AddProgrammingExams.cs:9-35
Example: Altering Existing Tables
The AddAIEvaluationExtendedFields migration adds new columns to the TaskProgresses and ProgrammingExamAttempts tables to support AI-based evaluation features.
// Migrations/20260108140205_AddAIEvaluationExtendedFields.cs:8-23
public partial class AddAIEvaluationExtendedFields : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "AICodeSnippets",
table: "TaskProgresses",
type: "nvarchar(max)",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "AISolutionSuggestion",
table: "TaskProgresses",
type: "nvarchar(max)",
nullable: true);
// ... other AddColumn calls
}
}
Sources: Migrations/20260108140205_AddAIEvaluationExtendedFields.cs:8-23
Model Snapshot
The Migrations/ApplicationDbContextModelSnapshot.cs file contains a complete snapshot of the current database model as understood by EF Core. It is automatically generated and updated whenever a new migration is added. EF Core compares the entity classes against this snapshot to determine the changes needed for the next migration. This file should not be edited manually.
Sources: Migrations/ApplicationDbContextModelSnapshot.cs
Application Startup and Database Initialization
The Program.cs file configures and runs the application, including the logic for database initialization.
This flowchart shows the database initialization process at application startup.
Sources: Program.cs:100-113
Applying Migrations
On application startup, the SeedDataAsync method is called. The first action within this method is to apply any pending migrations to the database using context.Database.MigrateAsync(). This ensures the database schema is up-to-date before the application begins serving requests.
Sources: Program.cs:122
Baseline Migrations
The project includes a custom helper function EnsureMigrationsBaselineAsync. This function is designed to handle a specific development scenario: if the database schema already exists (e.g., from a previous manual creation) but the __EFMigrationsHistory table is missing, this function creates the history table and inserts a record for the initial migration (20251130100008_InitialCreate). This "baselines" the database, allowing subsequent migrations to be applied without trying to re-create existing tables.
Sources: Program.cs:120, 180-247
Summary of Key Migrations
The following table summarizes some of the important migrations and the changes they introduced.
| Migration Name | Description | Affected Tables |
|---|---|---|
20251130100008_InitialCreate | Creates the initial database schema, including Identity tables and core entities like Courses, Exams, and Questions. | AspNetUsers, AspNetRoles, Courses, Exams, Questions, ExamAttempts, ExamCodes, etc. |
20251213133822_AddExamAppLaunch | Adds tables to support the secure desktop exam application, including ExamAppAuthorizations and ExamAppLaunchSessions. | ExamAppAuthorizations, ExamAppLaunchSessions |
20251223122534_AddProgrammingExams | Introduces the entire suite of tables for the programming exam feature. | ProgrammingExams, ProgrammingTasks, TestCases, ProjectFiles, ProgrammingExamAttempts, etc. |
20251225105704_AddAIEvaluationFields | Adds columns to TaskProgresses to store results from AI-based code evaluation. | TaskProgresses |
20260108140205_AddAIEvaluationExtendedFields | Extends AI evaluation by adding more fields to TaskProgresses and ProgrammingExamAttempts for teacher re-evaluation requests. | TaskProgresses, ProgrammingExamAttempts |
Sources: Migrations/20251130100008_InitialCreate.Designer.cs, Migrations/20251213133822_AddExamAppLaunch.cs, Migrations/20251223122534_AddProgrammingExams.cs, Migrations/20251225105704_AddAIEvaluationFields.cs, Migrations/20260108140205_AddAIEvaluationExtendedFields.cs
Conclusion
The Entity Framework Migrations system is a critical part of the PeP5 project's architecture. It provides a reliable and repeatable process for evolving the database schema in lockstep with application code changes. By defining the data model, relationships, and constraints in ApplicationDbContext and capturing schema changes in discrete migration classes, the project maintains a clear history of its database structure and automates the update process. The inclusion of startup logic to apply migrations and seed data ensures a consistent and correctly configured database environment.