Entity Framework Core in .NET Web API – A Practical Introduction
Introduction
In Day 9, we learned about DTOs and Model Validation in .NET Web API. We understood why we should not always expose database or entity models directly through API endpoints, how to create request and response DTOs, and how to validate incoming data.
Now let's understand another important part of backend development: how does our API communicate with a database?
Imagine we are developing an Employee Management application.
We have already created our Employee entity, request DTO, response DTO, and API controller. But where will employee information actually be stored?
How will we insert new employees, retrieve employee records, update information, and delete records from a database?
Traditionally, developers used SQL queries and database commands to perform these operations.
However, .NET provides a powerful Object-Relational Mapping (ORM) framework called Entity Framework Core (EF Core) that makes database operations easier using C# objects.
In this article, we will understand Entity Framework Core, explore its important components, and see how it works with a practical example.
1. What is Entity Framework Core?
Entity Framework Core (EF Core) is a modern, open-source Object-Relational Mapper (ORM) developed by Microsoft.
It allows developers to work with databases using C# classes and objects instead of writing SQL queries for every database operation.
In simple terms, EF Core acts as a bridge between our .NET application and a relational database.
For example, suppose we have an Employee class in our application.
public class Employee
{
public int EmployeeId { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public string Department { get; set; }
}Without an ORM, we would generally write SQL queries to insert, update, delete, and retrieve employee records.
With Entity Framework Core, we can work with C# objects and let EF Core translate supported operations into database-specific SQL queries.
This makes database interaction more convenient and allows developers to focus on application logic.
2. What is ORM (Object-Relational Mapping)?
Before understanding EF Core in detail, let's understand ORM.
ORM stands for Object-Relational Mapping.
It is a programming technique that maps application objects to relational database structures.
For example:
| C# Application | Database |
|---|---|
| Employee class | Employees table |
| EmployeeId property | EmployeeId column |
| FullName property | FullName column |
| Employee object | A row in the Employees table |
| DbContext | Manages database interaction |
Suppose we create an Employee object:
var employee = new Employee
{
FullName = "Rahul Sharma",
Email = "rahul@example.com",
Department = "IT"
};EF Core can track this object and, when saved, translate the operation into an appropriate SQL INSERT statement through the configured database provider.
We don't need to manually write the INSERT query for this operation.
This is the basic idea behind ORM.
3. Why Do We Use Entity Framework Core?
Let's understand why EF Core is commonly used in .NET applications.
1. Less manual SQL code
We can perform common database operations using C# objects and LINQ queries.
2. Strongly typed queries
We can write queries using C# properties and get compile-time assistance from our development environment.
3. Database migrations
EF Core provides a migration system to manage changes to our database schema over time.
4. Change tracking
EF Core can track changes made to entity objects and identify which database operations are required when changes are saved.
5. LINQ support
We can query data using Language Integrated Query (LINQ) instead of writing SQL for every operation.
6. Multiple database providers
EF Core supports different database systems through providers, including SQL Server, SQLite, PostgreSQL, and MySQL.
The exact provider and its configuration depend on the database we choose.
4. Important Components of Entity Framework Core
There are several important components we should understand before implementing EF Core.
Let's explore them one by one.
A. Entity
An entity is a C# class that represents a type of data managed by our application.
For example:
public class Employee
{
public int EmployeeId { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public decimal Salary { get; set; }
}This Employee class represents employee information.
When configured as an EF Core entity, it can be mapped to a database table.
B. DbContext
DbContext is one of the most important components of Entity Framework Core.
It represents a session with the database and coordinates database operations.
It is responsible for:
Managing entity objects.
Tracking changes.
Executing queries.
Saving changes to the database.
Managing database interactions.
Let's create a DbContext class.
Create a folder named Data and add a class called ApplicationDbContext.cs.
using Microsoft.EntityFrameworkCore;
using EmployeeManagementAPI.Entities;
namespace EmployeeManagementAPI.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(
DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
}
}Let's understand this code.
ApplicationDbContextinherits fromDbContext.DbContextOptionsprovides configuration for the context.DbSet<Employee>represents the collection of Employee entities that EF Core manages.
In a typical relational database setup, the Employees DbSet maps to the Employees table.
C. DbSet
DbSet represents a collection of entities that can be queried and managed through a DbContext.
For example:
public DbSet<Employee> Employees { get; set; }We can use this property to perform database operations on Employee records.
Some common operations include:
// Retrieve employees
var employees = await _context.Employees.ToListAsync();
// Find an employee
var employee = await _context.Employees.FindAsync(1);
// Add an employee
_context.Employees.Add(employee);
// Update an employee
_context.Employees.Update(employee);
// Delete an employee
_context.Employees.Remove(employee);
// Save changes
await _context.SaveChangesAsync();These examples assume that the DbContext is configured with a suitable database provider.
D. LINQ
LINQ stands for Language Integrated Query.
It allows us to query data using C# syntax.
For example, suppose we want to retrieve all employees belonging to the IT department.
Using EF Core:
var employees = await _context.Employees
.Where(e => e.Department == "IT")
.ToListAsync();We can also retrieve employees based on salary:
var employees = await _context.Employees
.Where(e => e.Salary > 50000)
.ToListAsync();EF Core translates supported LINQ expressions into SQL queries through the configured database provider.
This makes querying data convenient and readable.
5. Understanding How EF Core Works
Let's understand the overall flow of an EF Core database operation.
Suppose a client sends a request to create a new employee.
The process generally looks like this:
The client sends an HTTP request to the Web API.
The controller receives the request.
The application validates the incoming data.
The controller or service creates an Employee entity.
The entity is added to the DbContext.
SaveChangesAsync()is called.EF Core translates the required changes into database commands.
The configured database provider communicates with the database.
The application returns an appropriate HTTP response.
The following diagram represents this flow.
Client Application
|
| HTTP Request
v
.NET Web API Controller
|
v
Application Service
|
v
Entity Framework Core
|
v
ApplicationDbContext
|
v
Database Provider
|
v
SQL Server / Other Database
|
v
Database ResponseThe database provider is responsible for translating EF Core operations into commands understood by the selected database.
6. Practical Example – Employee Management Application
Now let's understand how we can use EF Core in a real .NET Web API project.
We will continue with our Employee Management application.
First, let's assume we already have the following Employee entity.
Create or update Employee.cs inside the Entities folder.
namespace EmployeeManagementAPI.Entities
{
public class Employee
{
public int EmployeeId { get; set; }
public string FullName { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Department { get; set; } = string.Empty;
public decimal Salary { get; set; }
}
}We have already created our ApplicationDbContext in the previous section.
Now let's understand how we can use it to perform database operations.
Step 1: Add the Entity Framework Core Package
To work with EF Core, we need the required NuGet packages.
Open the terminal in your project directory.
For the core EF Core functionality, execute:
dotnet add package Microsoft.EntityFrameworkCoreFor database operations, we also need a database provider.
For example, if we are using SQL Server, we will need:
dotnet add package Microsoft.EntityFrameworkCore.SqlServerImportant: Keep the EF Core package versions compatible with your application's target framework and with each other.
We will configure SQL Server and its connection string in our next article.
Step 2: Create the ApplicationDbContext
We already created the ApplicationDbContext class.
Let's look at it again:
using Microsoft.EntityFrameworkCore;
using EmployeeManagementAPI.Entities;
namespace EmployeeManagementAPI.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(
DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Employee> Employees { get; set; }
}
}This class acts as the central point through which our application interacts with EF Core.
Step 3: Understand Dependency Injection
In Day 8, we learned about Dependency Injection and how services can be registered in the .NET dependency injection container.
EF Core also integrates with Dependency Injection.
We register our DbContext so that controllers and services can receive it through constructor injection.
For a SQL Server application, the registration will look like this:
builder.Services.AddDbContext<ApplicationDbContext>(
options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
)
);This configuration uses the SQL Server provider and reads the connection string from application configuration.
We will configure this properly in Day 11 when we connect our Web API to SQL Server.
Step 4: Inject DbContext into a Service
Instead of directly writing database operations inside our controller, we can create a service.
Create an interface named IEmployeeService.cs.
using EmployeeManagementAPI.Entities;
namespace EmployeeManagementAPI.Services
{
public interface IEmployeeService
{
Task<IEnumerable<Employee>> GetAllEmployeesAsync();
Task<Employee?> GetEmployeeByIdAsync(int id);
Task<Employee> CreateEmployeeAsync(Employee employee);
}
}Now create EmployeeService.cs.
using EmployeeManagementAPI.Data;
using EmployeeManagementAPI.Entities;
using Microsoft.EntityFrameworkCore;
namespace EmployeeManagementAPI.Services
{
public class EmployeeService : IEmployeeService
{
private readonly ApplicationDbContext _context;
public EmployeeService(ApplicationDbContext context)
{
_context = context;
}
public async Task<IEnumerable<Employee>> GetAllEmployeesAsync()
{
return await _context.Employees.ToListAsync();
}
public async Task<Employee?> GetEmployeeByIdAsync(int id)
{
return await _context.Employees.FindAsync(id);
}
public async Task<Employee> CreateEmployeeAsync(Employee employee)
{
_context.Employees.Add(employee);
await _context.SaveChangesAsync();
return employee;
}
}
}Let's understand the important operations.
Add():
_context.Employees.Add(employee);Adds an entity to the DbContext and marks it as Added.
ToListAsync():
await _context.Employees.ToListAsync();Executes the query and retrieves the employee records.
FindAsync():
await _context.Employees.FindAsync(id);Finds an entity by its primary key. EF Core can first check its change tracker before querying the database.
SaveChangesAsync():
await _context.SaveChangesAsync();Persists the tracked changes to the database.
Step 5: Register the Service
Open Program.cs and register the EmployeeService.
builder.Services.AddScoped<IEmployeeService, EmployeeService>();We use the Scoped lifetime because a service using a DbContext should generally share the request-scoped DbContext instance.
The DbContext registration and SQL Server configuration will be completed in Day 11.
7. What Are EF Core Migrations?
Another important feature of Entity Framework Core is Migrations.
Migrations help us manage changes to our database schema as our application evolves.
For example, initially our Employee entity contains:
public class Employee
{
public int EmployeeId { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
}Later, we decide to add a Department property.
public string Department { get; set; }Now our application model has changed.
How do we apply this change to the database?
This is where EF Core Migrations help.
Migrations record changes to the model and generate the database schema operations required to bring the database up to date.
Common EF Core migration commands include:
Create a migration:
dotnet ef migrations add InitialCreateApply migrations to the database:
dotnet ef database updateTo use these commands, you need the EF Core tools and a configured database provider.
For example, the tools package can be installed using:
dotnet add package Microsoft.EntityFrameworkCore.DesignYou can also install the EF Core command-line tools if they are not already available:
dotnet tool install --global dotnet-efFor an existing installation, update the tool using:
dotnet tool update --global dotnet-efWe will explore database configuration and the actual migration workflow while connecting SQL Server in the next article.
8. EF Core vs Traditional ADO.NET
Many developers ask whether they should use Entity Framework Core or ADO.NET.
Both approaches are useful, but they work differently.
| Entity Framework Core | ADO.NET |
|---|---|
| ORM framework | Data access technology |
| Works with C# entities and LINQ | Uses database commands and SQL |
| Provides change tracking | Requires more manual data handling |
| Supports migrations | Schema changes are managed separately |
| Reduces repetitive data access code | Provides more direct control over SQL execution |
| Useful for common application data operations | Useful when fine-grained SQL control is required |
For example, with EF Core:
var employees = await _context.Employees
.Where(e => e.Department == "IT")
.ToListAsync();With ADO.NET, we would generally create a SQL command, execute it, and map the returned data ourselves.
Neither approach is universally better. The choice depends on the application's requirements, performance needs, and development approach.
9. When Should We Use Entity Framework Core?
EF Core is particularly useful when:
Building enterprise-level Web APIs.
Working with relational databases.
Managing application entities and relationships.
Performing common CRUD operations.
Using LINQ to query application data.
Managing database schema changes through migrations.
Maintaining applications with a structured data access layer.
However, for highly optimized reporting queries or complex database-specific operations, raw SQL or other data access approaches may sometimes be more appropriate.
A developer should understand both the benefits and limitations of the technology.
10. Important Things to Remember
Before moving to the next topic, let's revise the important concepts:
Entity Framework Core is an ORM developed by Microsoft.
ORM maps application objects to relational database structures.
An Entity represents a type of data managed by the application.
DbContext manages database interactions and entity tracking.
DbSet represents a collection of entities.
LINQ allows us to query data using C# syntax.
SaveChangesAsync() persists tracked changes.
Migrations help manage database schema changes.
Database providers allow EF Core to communicate with different database systems.
EF Core integrates with Dependency Injection in .NET applications.
Conclusion
Entity Framework Core makes database operations easier in .NET Web API applications by allowing developers to work with C# objects instead of manually writing SQL for every operation.
In this article, we explored ORM, entities, DbContext, DbSet, LINQ, Dependency Injection, and EF Core Migrations.
We also implemented a practical Employee Management example to understand how a service can use DbContext to retrieve and create employee records.
Understanding these concepts will help us build more maintainable and structured Web API applications.
But one important question remains: how do we actually connect our .NET Web API application to a real SQL Server database?
Let's explore that in our next article.
What's Next?
Day 11 – Connect to SQL Server
In the next article, we'll learn how to connect our .NET Web API application to SQL Server using Entity Framework Core. We'll configure the connection string, register the DbContext in Program.cs, and understand how our application communicates with the database.
Skills Tutorials – Learn • Build • Grow Together
Continue learning with our 30-day .NET Core Web API series.
No comments:
Post a Comment