Entity Framework (12), with New .Net Core MVC Code-First

Note: this article is published on 07/28/2024.

After I wrote several articles on this site, I found out it seemed almost for every article, I needed to set up a sample application associated with an entity framework if accessing the database. And, every time, I needed to rewrite the setup process from scratch in order for a new reader to follow along easily. Even for introducing a very simple concept, such as Caching, I needed to spend 80% of the time setting up the sample app, and only 20%  on introducing the Caching concept itself.

Therefore, I think it is better to write a basic model such as entity framework sample for various approaches, and then I can reuse them when needed. I made a list of the series of articles below, I will write them one by one, while the Entity framework overview and concept will be covered in the article (0):

Note

We write the Entity Framework for MVC module, but the pattern is the same or similar when applying to Web Application or Web API.

Introduction

This article is about Entity Framework with .Net Core MVC, Code-First approach. That is exactly the same topic of Entity Framework (4), with .Net Core MVC, Code-First, but the new version has different content. In fact, the content or the procedure is exactly the same as the Razor pages --- Entity Framework (11), with .Net Core Razor Pages Code-First

We will make a sample app step by step,

  • Step 1 - Create a .Net Core MVC app
  • Step 2 - Add a Model
  • Step 3 - Scaffold the Movie Model (Set up DbContext and Data Connection)
  • Step 4 - Migrate and Update database
  • Step 5 - Run the App and Test

At the end, we will have an .Net Core MVC module that can consume a database directly through entity framework.

Step 1 - Create a .Net Core MVC app

We use the current version of Visual Studio 2022 17.10.3 and .NET Core 8.0 to build the app:

  • Start Visual Studio and select Create a new project.
  • In the Create a new project dialog, select ASP.NET Core Web App (Model-View-Controller) > Next.
  • In the Configure your new project dialog, enter MvcMovie for Project name > Next.
  • In the Additional Information dialog, select .NET 8.0 (Long Term Support) in the target framework dropdowns > Create

Note

  1. In the Additional Information Page, do not select Enable container support. if you do, you might get this kind of error,
    • Platformnotsupportedexception localdb is not supported on this platforms
      • that is probably required to use linux container to held the database.
  2. For details, you may reference here.

Build and run the app, you will see the following image showing the app,

Step 2 - Add a Data Model

Add a data model, an entity class, into the app, with name as Movie:

  • In Solution Explorer, right click the Project > Add => New Folder, Name the folder as Models
  • Right click Models folder, > Add
  • In the Add New item dialog, Select Class, Enter the class name Movie > Add.
  • Add the code to the Movie class:
    using System.ComponentModel.DataAnnotations;
    
    namespace MvcMovie.Models;
    
    public class Movie
    {
        public int Id { get; set; }
        public string? Title { get; set; }
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string? Genre { get; set; }
        public decimal Price { get; set; }
    }

The Movie class contains:

  • The ID field is required by the database for the primary key.

  • [DataType] attribute that specifies the type of data in the ReleaseDate property. With this attribute:

    • The user isn't required to enter time information in the date field.
    • Only the date is displayed, not time information.
  • The question mark after string indicates that the property is nullable.

Step 3 - Scaffold the Movie Model (Set up DbContext and Data Connection)

This step is different from the previous, both 

for them, we needed to add DbContext and Data Connection code manually, then did the Scaffolding. Now, we go to scaffolding directly after setup the data model:

From Solution Explorer:

  • Right-click on the Controller folder > Add > New Scaffolded Item.

  • In the Add New Scaffolded Item dialog:
    • In the left pane, select Installed > Common > MVC.
    • Select MVC Controller with views, using Entity Framework.
    • Select Add.

  • Complete the Add MVC Controller with views, using Entity Framework dialog:

    • In the Model class drop down, select Movie (MvcMovie.Models).

    • lIn the Data context class row, select the + (plus) sign.

      1. In the New Add Data Context dialog, the class name MvcMovie.Data.MvcMovieContext is generated.
      2. In the Database provider drop down, select SQL Server.
      3. View and Conroller name, Keep the default.

Files created and updated

Scaffolding creates the following:

  • A movies controller: Controllers/MoviesController.cs
  • MVC view files for CreateDeleteDetailsEdit, and Index pages: Views/Movies/*.cshtml
  • A database context class: Data/MvcMovieContext.cs

Noted the difference between Razor pages and MVC module: MVC creates controller to handle the code while Razor pages create code behind .cshtml.cs files to handle the logic.

Scaffolding updates the following:

  • Registers the database context in the Program.cs file.
builder.Services.AddDbContext<MvcMovieContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MvcMovieContext") ?? throw new InvalidOperationException("Connection string 'MvcMovieContext' not found.")));
  • Adds a database connection string to the appsettings.json file.
  "ConnectionStrings": {
    "MvcMovieContext": "Server=(localdb)\\mssqllocaldb;Database=MvcMovieContext-a688ac71-10cb-4ce9-9a1b-178c1799ad7b;Trusted_Connection=True;MultipleActiveResultSets=true"
  }

Note 

As in .Net Framework MVC, you don't actually need to add connection string manually, even no need for DbContext, Entity Framework will create a LocalDB database in the users directory with the fully qualified name of the DbContext class.

Remember for the previous .Net Core version, say, 5.0, you  have to create a DbContext manually in code, and add a connection string in the appsettings.json file and have to register it in Startup file.  Otherwise, it will not work.

Step 4 - Migrate and Update database

The following is the exactly the same as what Razore page did.

This is the same as .Net Core 5.0, you have to Migrate and Update database before to make the app work.

 Click "Tools->NuGet Package Manager->Package Manager Console", and run the PMC command

Add-Migration InitialCreate

Two files created under Migration folder:

Run PMC command,

update-database 

Examine the database, before running the command:

After, the database MvcMovieContext-.... is created:

Tables created:

Seed the database

Create a new class named SeedData in the Models folder with the following code:

using Microsoft.EntityFrameworkCore;
using MvcMovie.Data;

namespace MvcMovie.Models;

public static class SeedData
{
    public static void Initialize(IServiceProvider serviceProvider)
    {
        using (var context = new MvcMovieContext(
            serviceProvider.GetRequiredService<
                DbContextOptions<MvcMovieContext>>()))
        {
            if (context == null || context.Movie == null)
            {
                throw new ArgumentNullException("Null MvcMovieContext");
            }

            // Look for any movies.
            if (context.Movie.Any())
            {
                return;   // DB has been seeded
            }

            context.Movie.AddRange(
                new Movie
                {
                    Title = "When Harry Met Sally",
                    ReleaseDate = DateTime.Parse("1989-2-12"),
                    Genre = "Romantic Comedy",
                    Price = 7.99M
                },

                new Movie
                {
                    Title = "Ghostbusters ",
                    ReleaseDate = DateTime.Parse("1984-3-13"),
                    Genre = "Comedy",
                    Price = 8.99M
                },

                new Movie
                {
                    Title = "Ghostbusters 2",
                    ReleaseDate = DateTime.Parse("1986-2-23"),
                    Genre = "Comedy",
                    Price = 9.99M
                },

                new Movie
                {
                    Title = "Rio Bravo",
                    ReleaseDate = DateTime.Parse("1959-4-15"),
                    Genre = "Western",
                    Price = 3.99M
                }
            );
            context.SaveChanges();
        }
    }
}

If there are any movies in the database, the seed initializer returns and no movies are added.

Add the seed initializer into program.cs page:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using MvcMovie.Data;
using MvcMovie.Models;

var builder = WebApplication.CreateBuilder(args);

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

// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    SeedData.Initialize(services);
}

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

such as

Step 5 - Run the App and Test

Setup the link in main page:

For convenience, you can update one line code in file Views/Movies/Shared/_Layout.chtml, replace index:

to Movies

Run the App, the final result will be:

Summary

The new MVC Code First approach is exactly the same procedure of the .NET Core Razor Pages module, except the scaffolding create

  • Controller + Views for MVC module
  • Views + Code behind for Razor Page

The .NET Core Razor Pages module/New MVC for Code-First approach is very similar to the MVC module and the .Net Core MVC Module, except something new

  1. No need to setup DbContext and Connection String manually, no need to register DbContext to Framework, all of them are auto done by Scaffolding
  2. Need to Migrate and Update database.

Comparing Razor with MVC, Core MVC modules, Razor is simply divide the long code first approach into thre major steps:

  1. Modle to set up front end data entity
  2. Scaffolding to setup front end code;
  3. PMC command to handle data migration and update. 

Razor Pages and MVC new approach:

  • Step 1 - Create a .Net Core Razor Page/MVC app
  • Step 2 - Add a Model
  • Step 3 - Scaffold the Movie Model (Set up DbContext and Data Connection)
  • Step 4 - Migrate and Update database
  • Step 5: Run the App and Test

MVC module:

  • Step 1: Create an ASP.NET MVC application
  • Step 2: Add a Model
  • Step 3: Set up DbContext
  • Step 4: Set up Data Connection
  • Step 5: Create Controller to access data from entity framework
  • Step 6: Run the App and Test

.Net Core MVC Module:

  • Step 1: Create an ASP.NET Core MVC application
  • Step 2: Add a Model
  • Step 3: Set up DbContext
  • Step 4: Set up Data Connection
  • Step 4.5: Migrate and Update database (this step is not necessary for .Net Framework MVC)
  • Step 5: Create Controller to access data from entity framework
  • Step 6: Run the App and Test

Reference


Similar Articles