A Step-by-Step Guide to Configuring Entity Framework in Your .NET Web API Project

Entity Framework (EF) is an Object-Relational Mapping (ORM) framework that enables developers to interact with databases in a more efficient and convenient way, rather than having to write raw SQL queries.

Entity Framework makes it easier to access data from the database by providing a simple and consistent way to interact with the data. Entity Framework supports multiple database providers, including SQL Server, MySQL, PostgreSQL, and SQLite, enabling developers to use a single data access layer to work with different databases.

But, how can you configure Entity Framework in a .NET Web API project?

I will be using:
– C#
– .NET 7
– Web API (you can also use MVC)
– SQL Server
– Visual Studio 2022 Community

You can get the initial state of the app in this GitHub repository master branch. In this project, you will see that you have a folder named Models and inside this folder, you will have the Student.cs class which will be used as a database model.

1 – Install NuGet Packages

To add Entity Framework Core (EF Core) to an ASP.NET Web API project, you need to first install all the necessary packages. Navigate to Tools > NuGet Package Manger > Manage NuGet Packages for Solution… Then, in the browser tab search for EntityFrameworkCore.

Find and install the following packages

  1. Microsoft.EntityFrameworkCore
  2. Microsoft.EntityFrameworkCore.SqlServer – This database provider allows Entity Framework Core to be used with Microsoft SQL Server (including Azure SQL Database).
  3. Microsoft.EntityFrameworkCore.Tools – It helps with design-time development tasks. They’re primarily used to manage Migrations and to scaffold a DbContext and entity types by reverse engineering the schema of a database.
2 – Create an Empty Database

Now, let us create a new SQL database using Visual Studio. In Visual Studio, navigate to View > Server Explorer.

Now that Server Explorer is opened, right-click on Data Connections > Create New SQL Server Database…

Create a New SQL Server Database wizard

Fill in all the necessary information and click the OK button. On the Server Explorer list, you will now see the database that you just created.

Server Explorer

Next, you need to right-click and select the Properties option and copy the Connection String property value, which in my case is:

Data Source=ETR\SQLEXPRESS;Initial Catalog=StudentApp-DNH-DB;Integrated Security=True;Pooling=False

This Database Connection String value needs to be stored in your Web API project, typically in the appsettings.json file. In this file, you need to create a “ConnectionStrings” section and inside here have a key-value pair where the value is the connection string value. After updated, the appsettings.json file would look like below:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "ConnectionStrings": {
    "DefaultValue": "Data Source=ETR\\SQLEXPRESS;Initial Catalog=StudentApp-DNH-DB;Integrated Security=True;Pooling=False"
  },
  "AllowedHosts": "*"
}
3 – Adding DbContext class

The DbContext class is the primary class in the Entity Framework that acts as a bridge between the domain (entity) classes and the database. It is responsible for managing the connection to the database, tracking changes to entities, and persisting those changes back into the database.

A DbContext class typically contains a number of DbSet properties, which represent the different entity sets that are being managed by the context. Each DbSet maps to a table in the database and provides methods for querying, adding, updating, and deleting entities.

Overall, the DbContext file is the primary class that is responsible for interacting with the database and it serves as the entry point for querying and saving data in the database using the Entity Framework.

To create this file, I will add a new folder named Data, inside this folder, I will add a C# class named AppDbContext

using Microsoft.EntityFrameworkCore;
namespace StudentApp.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        {
        }
    }
}

This code above defines a constructor for a class called AppDbContext that inherits from the DbContext class. The constructor takes a single parameter of type DbContextOptions<ApplicationDbContext>, which is used to configure the context.

The : base(options) is calling the base constructor of the DbContext class and passing in the options parameter. The DbContextOptions parameter is used to configure the context, such as setting the connection string, enabling lazy loading, and configuring the database provider to be used.

Next, you need to add the DbSet property for the Student.cs model

public DbSet<Student> Students { get; set; }

The Students property is a public property of the DbContext class and it is of type DbSet<Student>. It is exposed as public property so that it can be accessed from other parts of the application. This property represents the “Students” table in the database, and it can be used to query, insert, update, and delete Student entities.

4 – SQL Database Configuration

Now that we have installed the necessary NuGet packages, created the Database, created the DbContext file, and also created the DbSet<T> properties of DbContext, it is time to configure the SQL Server Database with the DbContext file so we can send and get data from the database using Entity Framework.

For that, you need to navigate to Program.cs class and add the following line:

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultValue")));

before,

var app = builder. Build();

This code is adding a DbContext (AppDbContext) to the services collection of an instance of the Microsoft.AspNetCore.Builder.IApplicationBuilder class, using the UseSqlServer method to configure the context to use a SQL Server database specified in the application’s configuration file (retrieved using builder.Configuration.GetConnectionString("DefaultValue")). DefaultValue is the value of the connection string that we have stored in the appsettings.json file.

The AddDbContext method is used to add the context to the services collection and the options parameter is used to configure the context.

The Program.cs now looks like this:

using Microsoft.EntityFrameworkCore;
using StudentApp.Data;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultValue")));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
5 – Migrations

Entity Framework Core Migrations is a feature that allows developers to manage changes to the database schema over time. It enables developers to create a set of scripts that can be used to create, update or delete the database schema to match the current state of the application’s entities.

The use of migrations allows a way of managing changes to the database schema, instead of manually making changes to the database or writing raw SQL scripts.

To add a migration, you need to go to Tools > Nuget Package Manager > Package Manager Console the type

Add-Migration Initial

Initial is just the name of this migration and you can name anything you want.

Add-Migration Initial command

Execution of this command will generate a migration file with the same name as your migrations, in this case, Initial, which inherits from the Migration base class.

6 – Database Update

Now, that the migration file is added, all you need to do is to execute another command to apply all the migration changes to the database, which you configured using the AddDbContext method in Program.cs file.

Update-Database

If this command is executed successfully, you can verify if the table was created by navigating to Server Explorer > Database Name > Tables where you should see a table named Students.

Server Explorer

You can also see that there is an additional table named, _EFMigrationsHistory.

The _EFMigrationsHistory table is a table created by Entity Framework Core (EF) to keep track of the applied migrations to a database. It is used to determine which migrations have been applied to a database and which ones still need to be applied.

When migrations are applied to a database, EF will insert a row into the _EFMigrationsHistory table for each migration that was applied, with the migration’s name and timestamp.

The _EFMigrationsHistory table is important because it is used to determine the current state of the database schema, and it is used to determine which migrations need to be applied when updating the database schema.

7 – Scaffold API Controller

Above we have seen how to configure Entity Framework in a .NET project. Now, let us create a new Controller, scaffold the controller with Entity Framework and check out the code.

You need to right-click in the Controllers folder, Add > Controller > API > API Controller with actions, using Entity Framework Core after you click add you need to fill in the pop-up with all the necessary information

API Controller with Entity Framework

This will create a controller named StudentsController which has all the CRUD API endpoints with Entity Framework. It looks like below:

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

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

        // GET: api/Students
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Student>>> GetStudents()
        {
          if (_context.Students == null)
          {
              return NotFound();
          }
            return await _context.Students.ToListAsync();
        }

        // GET: api/Students/5
        [HttpGet("{id}")]
        public async Task<ActionResult<Student>> GetStudent(int id)
        {
          if (_context.Students == null)
          {
              return NotFound();
          }
            var student = await _context.Students.FindAsync(id);

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

            return student;
        }

        // PUT: api/Students/5
        // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
        [HttpPut("{id}")]
        public async Task<IActionResult> PutStudent(int id, Student student)
        {
            if (id != student.Id)
            {
                return BadRequest();
            }

            _context.Entry(student).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!StudentExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return NoContent();
        }

        // POST: api/Students
        // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
        [HttpPost]
        public async Task<ActionResult<Student>> PostStudent(Student student)
        {
          if (_context.Students == null)
          {
              return Problem("Entity set 'AppDbContext.Students'  is null.");
          }
            _context.Students.Add(student);
            await _context.SaveChangesAsync();

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

        // DELETE: api/Students/5
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteStudent(int id)
        {
            if (_context.Students == null)
            {
                return NotFound();
            }
            var student = await _context.Students.FindAsync(id);
            if (student == null)
            {
                return NotFound();
            }

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

            return NoContent();
        }

        private bool StudentExists(int id)
        {
            return (_context.Students?.Any(e => e.Id == id)).GetValueOrDefault();
        }
    }

The final version of the project can be found in this GitHub repository, branch development.


Enjoyed this post? Subscribe to my YouTube channel for more great content. Your support is much appreciated. Thank you!


Check out my Udemy profile for more great content and exclusive learning resources! Thank you for your support.
Ervis Trupja - Udemy



Enjoyed this blog post? Share it with your friends and help spread the word! Don't keep all this knowledge to yourself.