Поиск  
Always will be ready notify the world about expectations as easy as possible: job change page
Jul 22

Code First approach in .NET 8 API

Автор:
Источник:
Просмотров:
2800

Introduction

In this article, we are going to discuss What Entity Framework is and How we can implement it in the .Net 8 project. This is a continuation of part 1, so if you are new to this article, please check my part 1 before proceeding. In this article, we are going to implement EF8 code first approach.

What is Entity Framework?

  • Entity Framework (EF) is an object-relational mapper that enables .NET developers to work with relational data using domain-specific objects.
  • It eliminates the need for most of the data-access code that developers usually need to write.
  • Its purpose is to abstract the ties to a relational database.

Why Entity Framework?

Entity Framework is an ORM, and ORMs are aimed to increase the developer’s productivity by reducing the redundant task of persisting the data used in our applications.

Features of Entity Framework

  • Entity Framework is a lightweight and extensible object-relational mapping (ORM) technology.
  • Entity Framework supports multiple platforms like Windows, Linux, and macOS.
  • Entity Framework supports both relational and non-relational data sources.
  • Entity Framework works efficiently with widely used databases like SQL Server, SQL Server Compact, SQLite, and PostgreSQL.
  • Entity Framework makes it easier for programmers to perform create, read, update, and delete (CRUD) operations by supporting databases. It also makes it easier for developers to perform unit testing by keeping in-memory tables.

Entity Framework development approaches

There are three approaches to creating entity frameworks.

Code First approach

The Code First approach enables us to create a model and relation using classes and then create the database from these classes. It enables us to work with the Entity Framework in an object-oriented manner. In this approach, you can use empty databases and add tables too.

Model First approach

In this approach, model classes and their relation are created first using the ORM designer, and the physical database will be generated using this model. The Model First approach means we create a diagram of the entity and relation that will be converted automatically into a code model.

Database First approach

The Database First approach enables us to create an entity model from the existing database. This approach helps us to reduce the amount of code that we need to write. The following procedure will create an entity model using the Database First approach.

Prerequisites

  • Visual Studio 2022 (any edition — Community / Professional / Enterprise)
  • Microsoft SQL Server 2008 or above.
  • .Net Core 8 SDK or later version

Steps to follow to Implement EF8

Step 1. Install Entity Framework Package from NuGet.

Right Click on your project -> Click on ”Manage NuGet Packages” -> Open “Browse” tab -> search below EF8 package

  1. Microsoft.EntityFrameworkCore
  2. Microsoft.EntityFrameworkCore.Design
  3. Microsoft.EntityFrameworkCore.Tools
  4. Microsoft.EntityFrameworkCore.SqlServer

Step 2. Add OurHeroDbContext file in our project.

  • Open a solution
  • Right-click and add the “Entity” folder
  • add OurHeroDbContext class (select “Entity” folder and press Ctrl + Shift + A to create a class)
  • inherit DbContext class
  • Add constructor and accept EF option and send to DbContext
// OurHeroDbContext.cs
using Microsoft.EntityFrameworkCore;

namespace DotNet8WebAPI.Entity
{
    public class OurHeroDbContext : DbContext
    {
        public OurHeroDbContext(DbContextOptions<OurHeroDbContext> options) : base(options)
        {
        }
    }
}

Step 3. Registered DB Model in OurHeroDbContext file.

Configured our EF model and loaded pre-defined data(master data).

// OurHeroDbContext.cs
using DotNet8WebAPI.Model;
using Microsoft.EntityFrameworkCore;

namespace DotNet8WebAPI.Entity
{
    public class OurHeroDbContext : DbContext
    {
        public OurHeroDbContext(DbContextOptions<OurHeroDbContext> options) : base(options)
        {
        }
        // Registered DB Model in OurHeroDbContext file
        public DbSet<OurHero> OurHeros { get; set; }

        /*
         OnModelCreating mainly used to configured our EF model
         And insert master data if required
        */
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Setting a primary key in OurHero model
            modelBuilder.Entity<OurHero>().HasKey(x => x.Id);

            // Inserting record in OurHero table
            modelBuilder.Entity<OurHero>().HasData(
                new OurHero
                {
                    Id = 1,
                    FirstName = "System",
                    LastName = "",
                    isActive = true,
                }
            );
        }
    }
}

Step 4. Add ConnectionStrings in appSettings.json file

"ConnectionStrings": {
  "OurHeroConnectionString": "Data Source=LAPTOP-4TSM9SDC;Initial Catalog=OurHeroDB; Integrated Security=true;TrustServerCertificate=True;"
}
// appSettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "ConnectionStrings": {
    "OurHeroConnectionString": "Data Source=LAPTOP-4TSM9SDC;Initial Catalog=OurHeroDB; Integrated Security=true;TrustServerCertificate=True;"
  },
  "AllowedHosts": "*"
}

Step 5. Register DbContext

Select your Database — I’m using an SQL server as a database. That’s why I called the UseSqlServer method.

Provide ConnectionString

//*********************** Register DbContext and provide ConnectionString .***********************
builder.Services.AddDbContext<OurHeroDbContext>(db => db.UseSqlServer(builder.Configuration.GetConnectionString("OurHeroConnectionString")), ServiceLifetime.Singleton);
//*********************** Register DbContext end.***********************
// Program.cs

using DotNet8WebAPI.Entity;
using DotNet8WebAPI.Services;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

//*********************** Add services to the container.***********************
builder.Services.AddTransient<IOurHeroService, OurHeroService>();
//*********************** Add services to the container end.***********************

//*********************** Register DbContext and provide ConnectionString .***********************
builder.Services.AddDbContext<OurHeroDbContext>(db => db.UseSqlServer(builder.Configuration.GetConnectionString("OurHeroConnectionString")), ServiceLifetime.Singleton);
//*********************** Register DbContext end.***********************

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

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();

Step 6. Go to OurHeroService and inject our OurHeroDbContext in the constructor.

// OurHeroService.cs

using DotNet8WebAPI.Entity;
using DotNet8WebAPI.Model;

namespace DotNet8WebAPI.Services
{
    public class OurHeroService : IOurHeroService
    {
        private readonly OurHeroDbContext _db;
        public OurHeroService(OurHeroDbContext db)
        {
            _db = db;
        }
    }
}

Step 7. Now use db context instead of in-memory collection to fetch OurHeros record.

Use async-await to fetch the OurHeros record asynchronously.

instead of returning pain object return as a Task<List<OurHero>>

List<OurHero> → Task<List<OurHero>>

// OurHeroService.cs

using DotNet8WebAPI.Entity;
using DotNet8WebAPI.Model;
using Microsoft.EntityFrameworkCore;

namespace DotNet8WebAPI.Services
{
    public class OurHeroService : IOurHeroService
    {
        private readonly OurHeroDbContext _db;
        public OurHeroService(OurHeroDbContext db)
        {
            _db = db;
        }

        public async Task<List<OurHero>> GetAllHeros(bool? isActive)
        {
            if (isActive == null) { return await _db.OurHeros.ToListAsync(); }

            return await _db.OurHeros.Where(obj => obj.isActive == isActive).ToListAsync();
        }

        public async Task<OurHero?> GetHerosByID(int id)
        {
            return await _db.OurHeros.FirstOrDefaultAsync(hero => hero.Id == id);
        }

        public async Task<OurHero?> AddOurHero(AddUpdateOurHero obj)
        {
            var addHero = new OurHero()
            {
                FirstName = obj.FirstName,
                LastName = obj.LastName,
                isActive = obj.isActive,
            };

            _db.OurHeros.Add(addHero);
            var result = await _db.SaveChangesAsync();
            return result >= 0 ? addHero : null;
        }

        public async Task<OurHero?> UpdateOurHero(int id, AddUpdateOurHero obj)
        {
            var hero = await _db.OurHeros.FirstOrDefaultAsync(index => index.Id == id);
            if (hero != null)
            {
                hero.FirstName = obj.FirstName;
                hero.LastName = obj.LastName;
                hero.isActive = obj.isActive;

                var result = await _db.SaveChangesAsync();
                return result >= 0 ? hero : null;
            }
            return null;
        }

        public async Task<bool> DeleteHerosByID(int id)
        {
            var hero = await _db.OurHeros.FirstOrDefaultAsync(index => index.Id == id);
            if (hero != null)
            {
                _db.OurHeros.Remove(hero);
                var result = await _db.SaveChangesAsync();
                return result >= 0;
            }
            return false;
        }
    }
}

Step 8. In IOurHeroService.

Update method return type.

Return as a Task instead of the normal class model.

Task<List<OurHero>> GetAllHeros(bool? isActive);
// IOurHeroService.cs
using DotNet8WebAPI.Model;

namespace DotNet8WebAPI.Services
{
    public interface IOurHeroService
    {
        Task<List<OurHero>> GetAllHeros(bool? isActive);
        Task<OurHero?> GetHerosByID(int id);
        Task<OurHero?> AddOurHero(AddUpdateOurHero obj);
        Task<OurHero?> UpdateOurHero(int id, AddUpdateOurHero obj);
        Task<bool> DeleteHerosByID(int id);
    }
}

Step 9. Open OurHeroController file.

Implement async-await in all action methods because now our IOurHeroService returns a response asynchronously.

[HttpGet]
public async Task<IActionResult> Get([FromQuery] bool? isActive = null)
{
    var heros = await _heroService.GetAllHeros(isActive);
   
    return Ok(heros);
}
// OurHeroController.cs
using DotNet8WebAPI.Model;
using DotNet8WebAPI.Services;
using Microsoft.AspNetCore.Mvc;

namespace DotNet8WebAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class OurHeroController : ControllerBase
    {
        private readonly IOurHeroService _heroService;
        public OurHeroController(IOurHeroService heroService)
        {
            _heroService = heroService;
        }

        [HttpGet]
        public async Task<IActionResult> Get([FromQuery] bool? isActive = null)
        {
            var heros = await _heroService.GetAllHeros(isActive);
            return Ok(heros);
        }

        [HttpGet("{id}")]
        //[Route("{id}")] // /api/OurHero/:id
        public async Task<IActionResult> Get(int id)
        {
            var hero = await _heroService.GetHerosByID(id);
            if (hero == null)
            {
                return NotFound();
            }
            return Ok(hero);
        }

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] AddUpdateOurHero heroObject)
        {
            var hero = await _heroService.AddOurHero(heroObject);

            if (hero == null)
            {
                return BadRequest();
            }

            return Ok(new
            {
                message = "Super Hero Created Successfully!!!",
                id = hero!.Id
            });
        }

        [HttpPut]
        [Route("{id}")]
        public async Task<IActionResult> Put([FromRoute] int id, [FromBody] AddUpdateOurHero heroObject)
        {
            var hero = await _heroService.UpdateOurHero(id, heroObject);
            if (hero == null)
            {
                return NotFound();
            }

            return Ok(new
            {
                message = "Super Hero Updated Successfully!!!",
                id = hero!.Id
            });
        }

        [HttpDelete]
        [Route("{id}")]
        public async Task<IActionResult> Delete([FromRoute] int id)
        {
            if (!await _heroService.DeleteHerosByID(id))
            {
                return NotFound();
            }

            return Ok(new
            {
                message = "Super Hero Deleted Successfully!!!",
                id = id
            });
        }
    }
}

Step 10. Now, our Entity Framework integration is almost ready.

Next:

Visual Studio

  • Open the Tools menu (available in the Visual Studio toolbar)
  • Select NuGet package manager
  • Then Select Package Manager Console

NuGet package manager

Package Manager Console

Run the add-migration [name] command to generate a DB migration file.

Once the file is ready:

DB migration file

Then, run the update-database command to reflect the migration change on our database side.

update-database

After running the update-database command. If you are also getting the same Error.

Only the invariant culture is supported in the globalization-invariant mode.

Then follow the below stem to fix this issue.

  • Open a solution explorer
  • Double-click on your project
  • It will open the .csproj file
  • update the InvariantGlobalization setting from true to false (It’s available in the PropertyGroup section)
  • Save .csproj file
  • Run the update-database command again

Once the updated database runs successfully, you will verify your Database in the SQL Server like this.

Database in the SQL Server

Step 11. Now, our Entity Framework has been implemented successfully.

We can run our application and verify.

Verify application

Currently, we have one entry because we are inserted using the OnModelCreating method.

Now, I’m going to insert one more entry using post-API (/api/OurHero)

post-API

Summary

That’s it! You’ve created a complete .NET 8 Web API for CRUD operations with an SQL Server database. You can now integrate this API into your front-end application.


Thanks for reading.

Похожее
Dec 1, 2020
Author: Guy Levin
While there are as many proprietary authentication methods as there are systems which utilize them, they are largely variations of a few major approaches. In this post, I will go over the 4 most used in the REST APIs and...
Sep 5
Author: Jay Krishna Reddy
Introduction According to the people who designed it, OData (the Open Data Protocol) is “the best way to Rest”. OData is essential, a way to try and standardize REST. It’s an open protocol that allows the creation and consumption of...
Feb 17, 2023
Author: Juldhais Hengkyawan
A Guide to Building Scalable, Maintainable Web API using ASP .NET Core The term “Clean Architecture” has become increasingly popular in software development in recent years. Clean Architecture is a software design pattern that prioritizes the separation of concerns, making...
Jun 27, 2023
Author: Anton Selin
Introduction Performance optimization is a key concern in software development, regardless of the programming language or platform you’re using. It’s all about making your software run faster or with less memory consumption, leading to better user experience and more efficient...
Написать сообщение
Тип
Почта
Имя
*Сообщение