A backend-focused Student Management System built with C#, .NET 8, Entity Framework Core, and SQL Server.
The project was developed to practice and demonstrate real-world database-driven application development using Entity Framework Core, including entity relationships, CRUD operations, LINQ queries, tracking behavior, eager loading, soft deletion, global query filters, data seeding, migrations, asynchronous database operations, and manual integration testing.
The system manages:
- Students
- Courses
- Enrollments
- Instructors
- Student grades
- Course-instructor assignments
The project focuses on building a simple and practical EF Core data layer without unnecessary abstractions or over-engineering.
The main goal was to understand how application code interacts with a relational database through Entity Framework Core and how to design, query, and manage related entities effectively.
- Add a student
- Get student by ID
- Update student information
- Soft delete a student
- Search students by name
- Get a student with all enrollments
- Retrieve deleted students when explicitly required
- Add a course
- Get course by ID
- Update course information
- Delete a course
- Add an enrollment
- Get enrollment by Student ID and Course ID
- Update enrollment
- Delete enrollment
- Get all students enrolled in a specific course
- Get all courses and grades for a specific student
- Calculate the average grade for a course
- Model instructors as separate entities
- Support many-to-many relationships between courses and instructors
- Store the instructor's role for each course assignment
- SQL Server integration
- Entity Framework Core migrations
- Static database seeding using
HasData() - Composite keys
- Foreign key relationships
- Navigation properties
- Global query filters
- Soft deletion
| Technology | Purpose |
|---|---|
| C# | Programming language |
| .NET 8 | Application framework |
| Entity Framework Core | ORM and database access |
| SQL Server | Relational database |
| LINQ | Database querying |
| Visual Studio | Development environment |
| Git & GitHub | Version control |
The project follows a simple service-based architecture:
Application
โ
Services
โ
AppDbContext
โ
Entity Framework Core
โ
SQL Server
The project intentionally avoids unnecessary architectural layers such as:
- Generic Repository
- Unit of Work
- Service Interfaces
- Controllers
- Additional abstraction layers
These were not required for the project scope, so the implementation remains simple and focused on understanding EF Core and database operations.
StudentManagementSystem/
โโโ Data/
โ โโโ AppDbContext.cs
โ
โโโ Entities/
โ โโโ Student.cs
โ โโโ Course.cs
โ โโโ Enrollment.cs
โ โโโ Instructor.cs
โ โโโ CourseInstructor.cs
โ
โโโ Services/
โ โโโ StudentService.cs
โ โโโ CourseService.cs
โ โโโ EnrollmentService.cs
โ
โโโ Migrations/
โ
โโโ Program.cs
โโโ appsettings.json
โโโ StudentManagementSystem.csproj
Represents a student in the system.
Main properties:
- StudentId
- FName
- LName
- IsDeleted
A student can have multiple enrollments.
Student
โ
Enrollment
Represents an academic course.
Main properties:
- Id
- Title
- Credits
- Description
A course can have:
- Multiple enrollments
- Multiple instructors
Represents the relationship between a student and a course.
Main properties:
- StudentId
- CourseId
- Grade
- EnrollmentDate
The enrollment connects:
Student
โ
Enrollment
โ
Course
The combination of StudentId and CourseId identifies an enrollment and prevents the same student from being enrolled in the same course more than once.
Represents an instructor.
Main properties:
- InstructorId
- FName
- LName
Represents the many-to-many relationship between courses and instructors.
Main properties:
- InstructorId
- CourseId
- Role
Relationship:
Instructor
โ
CourseInstructor
โ
Course
A course can have multiple instructors, and an instructor can teach multiple courses.
The Role property allows the relationship itself to store information such as:
- Main Instructor
- Lead Instructor
- Assistant Instructor
Student โ Enrollment: One-to-Many
Course โ Enrollment: One-to-Many
Student โ Course: Many-to-Many through Enrollment
Course โ Instructor: Many-to-Many through CourseInstructor
Overall relationship:
Student
โ
Enrollment
โ
Course
โ
CourseInstructor
โ
Instructor
The service implements:
- Add Student
- Get Student By ID
- Update Student
- Soft Delete Student
- Search Student By Name
- Get Student With All Enrollments
- Get Deleted Students
The service implements:
- Add Course
- Get Course By ID
- Update Course
- Delete Course
The service implements:
- Add Enrollment
- Get Enrollment By Student And Course
- Update Enrollment
- Delete Enrollment
- Get Students In Course
- Get Courses And Grades By Student
- Calculate Average Grade
LINQ is used extensively for database querying through Entity Framework Core.
Used to filter entities based on specific conditions.
Examples include:
- Filtering enrollments by StudentId
- Filtering enrollments by CourseId
- Filtering students by name
- Filtering deleted students
Used for projection when only specific data is required.
For example:
Enrollment
โ
Student
Used when a query should return one entity or null.
Used for retrieving entities using their primary key or composite key.
Used when retrieving multiple records.
Used to calculate the average grade for a course.
Database operations are implemented asynchronously to avoid blocking while waiting for database I/O operations.
The project uses:
- AddAsync()
- FindAsync()
- FirstOrDefaultAsync()
- ToListAsync()
- AverageAsync()
- SaveChangesAsync()
This keeps database access asynchronous throughout the service layer.
The project demonstrates EF Core Change Tracking and No-Tracking queries.
Read-only queries use:
AsNoTracking()
This is appropriate when entities are only being read or displayed and do not need to be modified afterward.
Examples include:
- Get Student
- Search Students
- Get Course
- Get Enrollment
- Get Students In Course
- Get Courses And Grades
Tracking is preserved when an entity needs to be modified.
The general flow is:
Find Entity
โ
Entity becomes tracked
โ
Modify Entity
โ
SaveChangesAsync()
EF Core then detects the changes through the Change Tracker.
Related entities are loaded explicitly using Include() when related data is required.
Examples include:
Student
โ
Enrollments
and:
Enrollment
โ
Course
Eager loading makes the required relationships explicit and avoids unnecessary additional database queries when related data is required.
The project implements Soft Delete for students.
Instead of physically deleting the database record, the application changes:
IsDeleted = false
to:
IsDeleted = true
The database row remains available.
Example:
Before:
Student
IsDeleted = false
After Soft Delete:
Student
IsDeleted = true
This preserves the record while keeping it hidden from normal application queries.
A Global Query Filter is configured for the Student entity.
The filter conceptually applies:
!IsDeleted
to normal Student queries.
Therefore:
IsDeleted = falseโ Student is visibleIsDeleted = trueโ Student is hidden
This means normal Student queries automatically exclude soft-deleted records without manually adding a Where(IsDeleted == false) condition to every query.
When deleted students need to be explicitly retrieved, the Global Query Filter can be ignored for a specific query using:
IgnoreQueryFilters()
The query can then explicitly filter for:
IsDeleted = true
This allows the application to retrieve deleted records when required while keeping them hidden from normal queries.
Static test data is provided using EF Core HasData().
The seeded database contains:
- Multiple active students
- Multiple students with the same first name for search testing
- A soft-deleted student
- C# Fundamentals
- SQL Server
- EF Core
- ASP.NET Core
Multiple instructors are seeded to test instructor relationships.
Courses are assigned to instructors, including a course with multiple instructors.
Enrollments contain:
- Student
- Course
- Grade
- Enrollment Date
The seed data intentionally includes:
- Different grades
- A nullable grade
- Multiple students in the same course
- Multiple courses for the same student
- A course without enrollments
- A soft-deleted student
This makes the seed data useful for testing normal scenarios and edge cases.
The project uses manual integration testing rather than a unit-testing framework.
The tests execute the actual:
Service
โ
AppDbContext
โ
Entity Framework Core
โ
SQL Server
This allows the project to verify real database behavior instead of testing service logic in isolation.
- Get existing student
- Get non-existing student
- Search students by name
- Get student with enrollments
- Add student
- Update student
- Soft delete student
- Verify deleted student is hidden
- Retrieve deleted students
- Get existing course
- Get non-existing course
- Add course
- Update course
- Delete course
- Get enrollment by student and course
- Get all students in a course
- Get courses and grades for a student
- Calculate average grade
- Handle nullable grades
- Handle courses with no grades
- Add enrollment
- Update enrollment
- Delete enrollment
Ahmed Adel โ 85
Ahmed Hassan โ 75
Omar Mohamed โ 95
Youssef Samir โ 65
Expected average:
(85 + 75 + 95 + 65) / 4 = 80
Ahmed Adel โ 90
Ahmed Hassan โ NULL
Sara Ali โ 70
Expected average:
(90 + 70) / 2 = 80
The nullable grade is not treated as a numeric grade.
This project was used to practice and understand:
- DbContext
- DbSet
- Entity relationships
- Primary keys
- Composite keys
- Foreign keys
- Navigation properties
- Include()
- Where()
- Select()
- FirstOrDefaultAsync()
- FindAsync()
- ToListAsync()
- AverageAsync()
- AsNoTracking()
- Change Tracking
- SaveChangesAsync()
- Global Query Filters
- IgnoreQueryFilters()
- Soft Delete
- HasData()
- EF Core Migrations
- Async/Await
- SQL Server integration
EF Core migrations are used to keep the database schema synchronized with the application's entity model.
Typical workflow:
Modify Entity
โ
Create Migration
โ
Review Migration
โ
Update Database
Example using Package Manager Console:
Add-Migration InitialCreate
Update-Database
Or using .NET CLI:
dotnet ef migrations add InitialCreate
dotnet ef database update
Make sure the following are installed:
- .NET 8 SDK
- SQL Server
- Visual Studio
- Entity Framework Core tools
git clone <repository-url>
cd StudentManagementSystem
Update the connection string according to your SQL Server instance.
Example:
Server=.\SQLEXPRESS;Database=StudentManagementDb;Trusted_Connection=True;TrustServerCertificate=True;
Replace the Server value if a different SQL Server instance is being used.
dotnet restore
If migrations already exist:
dotnet ef database update
Or from Visual Studio Package Manager Console:
Update-Database
dotnet run
EF Core already provides a powerful data-access abstraction through DbContext and DbSet.
For this project's scope, adding a Repository layer would introduce another abstraction without providing enough value.
Therefore, the services communicate directly with AppDbContext.
The project does not require multiple implementations of the services.
Adding interfaces would increase the number of abstractions without a practical requirement, so the services are used directly.
The project requirements focus on:
- Entity Framework Core
- Database operations
- Services
- LINQ
- Entity relationships
- Data seeding
- Migrations
- Testing
A REST API layer was therefore not necessary for the current scope.
The project demonstrates how to:
- Design relational entities
- Model one-to-many relationships
- Model many-to-many relationships
- Work with composite keys
- Use foreign keys and navigation properties
- Query related data using LINQ
- Understand EF Core Change Tracking
- Use AsNoTracking() for read-only queries
- Load related entities using Include()
- Perform asynchronous database operations
- Implement Soft Delete
- Apply Global Query Filters
- Override filters using IgnoreQueryFilters()
- Seed realistic test data
- Apply EF Core migrations
- Test the service-to-database workflow
The current implementation intentionally stays within the project's scope.
Potential future improvements include:
- REST API Controllers
- DTOs
- Input validation
- Global exception handling
- Pagination
- Authentication and Authorization
- Logging
- Automated Unit Testing
- Automated Integration Testing
- API documentation
- More advanced dependency injection
- Repository abstraction if the project grows significantly
Developed as a practical .NET 8 and Entity Framework Core project focused on relational database development, EF Core querying, entity relationships, asynchronous database operations, and backend service design.
Build simple.
Understand deeply.
Avoid unnecessary abstraction.