ASP.NET databases by using Entity Framework Core in Core

Page creation date :

environment

Visual Studio
  • Visual Studio 2019
ASP.NET Core
  • 3.1 (MVC, Razor page)
SQL Server
  • 2019 Express

At first

This tips ASP.NET steps to use Entity Framework Core using the Following Core approach.

Creating a database, using Entity Framework Core, and so on are not the main focus of this tips, so we won't go into details. They ASP.NET used in the same way outside of Core.

This time, sql server is installed on a different server and connected by SQL Server authentication. The only difference from Windows authentication used during a local installation is the connection string, and there is no difference in the program.

Create a database table

This Tips uses SQL Server. Install SQL Server in your local environment or on any server.

If you do not have a database for testing, create a database.

If you are creating in SQL, such as the following, change the SQL Server version path and database name to suit your environment.

USE [master]
GO

CREATE DATABASE [TestDatabase]
  CONTAINMENT = NONE
  ON  PRIMARY 
( NAME = N'TestDatabase', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL15.SQLEXPRESS\MSSQL\DATA\TestDatabase.mdf' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
  LOG ON 
( NAME = N'TestDatabase_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL15.SQLEXPRESS\MSSQL\DATA\TestDatabase_log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB )
  WITH CATALOG_COLLATION = DATABASE_DEFAULT
GO

Create a table for testing. Set the primary key for updates and deletions.

If you want to create it in SQL:

USE [TestDatabase]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[User](
  [ID] [int] NOT NULL,
  [Name] [nvarchar](20) NOT NULL,
  [Password] [nvarchar](20) NOT NULL,
  [Age] [int] NULL,
  [Email] [nvarchar](200) NULL,
  [Birthday] [date] NULL,
  [UpdateDateTime] [datetime2](7) NULL,
  CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
  [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

Add a record for display.

If you want to add it in SQL:

USE [TestDatabase]
GO
INSERT [dbo].[User] ([ID], [Name], [Password], [Age], [Email], [Birthday], [UpdateDateTime]) VALUES (1, N'氏名1', N'aaaa', 20, N'aaaa@example.com', CAST(N'2020-04-01' AS Date), CAST(N'2021-03-14T00:00:00.0000000' AS DateTime2))
GO
INSERT [dbo].[User] ([ID], [Name], [Password], [Age], [Email], [Birthday], [UpdateDateTime]) VALUES (2, N'氏名2', N'bbbb', 30, N'bbbb@example.com', CAST(N'2010-04-01' AS Date), CAST(N'2021-03-14T00:00:00.0000000' AS DateTime2))
GO

ASP.NET entity framework available in Core

This item is common to both MVC and Razor pages.

Package installation of Entity Framework Core

Once you've created your project, get the package from NuGet so that you can use Entity Framework Core first. MVC is an example, but the operation is the same on razor pages.

Right-click Dependencies from the project and select Manage NuGet packages.

With Browse selected from the tab, type EntityFrameworkCore in the search field. The Entity Framework Core-related packages appear in the list.

From this time, I will use SQL Server, so I will install the following packages.

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.EntityFrameworkCore.SqlServer

Let's install Microsoft.EntityFrameworkCore as an example, so install the other two as well.

Select what you want to install, and then click the install button. The version selects the latest stabilizer.

The dialog is basically ok to click ok.

Install the other two as well.

I think that the package is as follows.

Create a model (program) from a database table configuration

If you want to retrieve or update data from a database in Entity Framework Core, You usually need to create a program that is a model based on the table configuration. This model is also called an alias entity.

When you create a model, code first, a technique for creating tables in a database from a model (program), or There is database first, which is a technique for creating models (programs) from tables. Here's a simple database-first way to automatically program from a table.

By the way, these steps are ASP.NET to The Core, so you can create them in the console or desktop app in the same way.

First, build the project once to make sure there are no errors. If there is an error, the model cannot be created. You don't need to built it if you've already verified that there are no errors.

From Visual Studio, open the Package Manager console. Otherwise, you can open it from the tools, NuGet Package Manager, and Package Manager consoles in the menu.

You'll see a window similar to the one below, so make sure that the Default Project at the top right is the project you want to model. (You need to be careful if you have multiple projects)

In the input field, type the following text: The parameters vary depending on the environment, so please change them in a timely manner to the following description. (especially where it's ***** in particular)

Scaffold-DbContext -Provider Microsoft.EntityFrameworkCore.SqlServer -Connection "Data Source=********\SQLEXPRESS;Database=TestDatabase;user id=********;password=**********" -f -OutputDir "Models\Database" -Context "TestDatabaseDbContext" -UseDatabaseNames -DataAnnotations

A hyphenated -Provider one, such as at the head of each name, is the parameter name, followed by the value of that parameter.

Parameter Description Parameter Example
Provider Fixed in Microsoft.EntityFrameworkCore.SqlServer SQL Server. Microsoft.EntityFrameworkCore.SqlServer
Connection Connection string for connecting to the database. Connection strings can be used in other apps in common, so please write what you specify according to the connection string kineki. Both Windows authentication and SQL Server authentication are available. By the way, it is only temporarily used to create a model, so you do not need to be aware of the security after the app is published for this connection string. Beware of escaping if you have a symbol in your password. "Data Source=ServerName\SQLEXPRESS;Database=TestDatabase;user id=UserName;password=**********"
f Force overwriting even if there is already a program. <No >
OutputDir The folder path to which the code is output. Relative path from project folder Models\Database
Context Context class name when using the Entity Framework TestDatabaseDbContext
UseDatabaseNames If specified, the table name of the database becomes the class name as it is. Otherwise, the case and the multiple form of the entity class name are adjusted according to the rules. <No >
DataAnnotations If specified, the column type automatically appends the DataAnnotation attribute to each property. This is a bit useful if you want to automatically check the input according to the type of the database. <No >

Pressing Enter to run it will automatically generate code as follows:

The model code for the User table is as follows:

[Table("User")]
public partial class User
{
  [Key]
  public int ID { get; set; }
  [Required]
  [StringLength(20)]
  public string Name { get; set; }
  [Required]
  [StringLength(20)]
  public string Password { get; set; }
  public int? Age { get; set; }
  [StringLength(200)]
  public string Email { get; set; }
  [Column(TypeName = "date")]
  public DateTime? Birthday { get; set; }
  public DateTime? UpdateDateTime { get; set; }
}

By the way, the warning is displayed because the connection string is listed as it is in the code of the generated context class. Be sure to delete OnConfiguring the methods in this context class after the code is generated.

Register connection strings

This ASP.NET core-specific processing. (If you customize it, you can use it in other .NET Core apps, but ASP.NET you can handle it by default for Core.)

The connection string specified in the Package Manager console was used only to generate the model.

The connection string for connecting to the database as a web app is listed in appsettings.json. If you want to change the database destination to connect to for each build or publication, you can use appsettings. It can also be branched by Development.json, etc.

In addition, since the connection string here is used as operation, let's take measures such as making the connection user a dedicated user in consideration of security etc.

If you set it to appsettings.json, create a ConnectionStrings section in the root section (an object, not exactly a section). Create a set of keys and values in it. The name of the key can be anything, but it will be used later. The value specifies a connection string.

{
  // 

  "ConnectionStrings": {
    "TestDatabaseDbContext": "Data Source=ServerName\\SQLEXPRESS;Database=TestDatabase;user id=UserName;password=********"
  }
}

Make Entity Framework Core available to programs

This ASP.NET core-specific processing. (If you customize it, you can use it in other .NET Core apps, but ASP.NET you can handle it by default for Core.)

ASP.NET Core, each instance has a survival time, which is different from consoles and desktop apps. For example, "From the time the Web service is started until it is stopped" or "from the time the request is received until the response is returned". ASP.NET framework Core, which can be placed in The Core, ServiceLifetime.Scoped specifies by default. If there is no special reason, you can stay this way.

To allow your program to access the database context, add Startup.ConfigureServices it to :

// 追加 (自前のクラスなので名前空間は適時合わせてください)
using DatabaseEntityFrameworkCoreMvc.Models.Database;

// 追加
using Microsoft.EntityFrameworkCore;

public class Startup
{
  // 省略

  // このメソッドはランタイムによって呼び出されます。 このメソッドを使用して、コンテナーにサービスを追加します。
  public void ConfigureServices(IServiceCollection services)
  {
    // 省略

    // 追加
    services.AddDbContext<TestDatabaseDbContext>(
      options => options.UseSqlServer(Configuration.GetConnectionString("TestDatabaseDbContext")));
  }

  // 省略

services.AddDbContext<TestDatabaseDbContext> The type argument of the method specifies the context class that you created.

options.UseSqlServer The method indicates that sql server is used.

Configuration.GetConnectionString("TestDatabaseDbContext") specifies the key name registered with appsettings.json.

ASP.NET use case in Core MVC

ASP.NET are several ways to use Entity Framework Core in Core MVC.

Add di (dependency insert) to a controller

By registering .cs services.AddDbContext method in startup.cs TestDatabaseDbContext It can be inserted into the controller.

An example of DI HomeController is that the constructor has an ILogger<HomeController> logger argument. This is added by DI. You can insert TestDatabaseDbContext in the same way.

If you HomeController want to add to an existing , it looks like this: Of course, it can be added to other controllers.

using DatabaseEntityFrameworkCoreMvc.Models.Database;  // 追加

// 省略

public class HomeController : Controller
{
  private readonly ILogger<HomeController> _logger;
  
  // 追加
  private readonly TestDatabaseDbContext _dbContext;
  
  public HomeController(ILogger<HomeController> logger, TestDatabaseDbContext dbContext)  // 追加
  {
    _logger = logger;
    _dbContext = dbContext;  // 追加
  }
  
  // 省略
}

You can then access the database by using the instance of the received context in each action.

Use cases

The following code is the code that handles user listing and new registrations. From now on ASP.NET core, Entity Framework Core will be code for each, so I will not explain in detail.

The entity Framework Core-generated model can still be used as a model for actions. You can also create a separate model and wrap and use the Entity Framework Core model.

Also, the context is automatically discarded when the user's request is over.

HomeController.cs

public class HomeController : Controller
{
  private readonly TestDatabaseDbContext _dbContext;

  // 省略

  // ここから追加

  /// <summary>
  /// ユーザー一覧表示アクション。
  /// </summary>
  public IActionResult List()
  {
    // データベースから User 一覧を取得する
    var users = _dbContext.Users.ToList();
    
    // ビューに渡す
    return View(users);
  }
  
  /// <summary>
  /// ユーザー一新規登録画面。
  /// </summary>
  public IActionResult Create()
  {
    return View();
  }
  
  /// <summary>
  /// ユーザー新規登録処理。
  /// </summary>
  [HttpPost]
  public IActionResult Create(User user)
  {
    // エラーがある場合は登録画面に戻る
    if (ModelState.IsValid == false) View(user);
    
    // 更新日時設定
    user.UpdateDateTime = DateTime.Now;

    // 登録リストにユーザー追加
    _dbContext.Users.Add(user);

    // 登録を確定する
    _dbContext.SaveChanges();
    
    // 一覧画面に遷移
    return RedirectToAction(nameof(List));
  }

  // ここまで追加

  // 省略
}

Since it is troublesome to create the screen manually, the list screen is automatically generated by scaffolding.

The Views/Home/List.cshtml auto-generated is as follows:

@model IEnumerable<DatabaseEntityFrameworkCoreMvc.Models.Database.User>

@{
  ViewData["Title"] = "List";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>List</h1>

<p>
  <a asp-action="Create">Create New</a>
</p>
<table class="table">
  <thead>
    <tr>
      <th>
        @Html.DisplayNameFor(model => model.ID)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Name)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Password)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Age)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Email)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Birthday)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.UpdateDateTime)
      </th>
      <th></th>
    </tr>
  </thead>
  <tbody>
@foreach (var item in Model) {
    <tr>
      <td>
        @Html.DisplayFor(modelItem => item.ID)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Name)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Password)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Age)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Email)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Birthday)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.UpdateDateTime)
      </td>
      <td>
        @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
        @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
        @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
      </td>
    </tr>
}
  </tbody>
</table>

Index.cshtml Add a link to the screen transition to the list.

<!-- 省略 -->

<ul>
  <li><a asp-action="List">List</a></li>
</ul>

The user registration screen is also automatically generated.

The Views/Home/Create.cshtml auto-generated is as follows: It is difficult to use as it is, so I have fixed it a little.

@model DatabaseEntityFrameworkCoreMvc.Models.Database.User

@{
  ViewData["Title"] = "Create";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Create</h1>

<h4>User</h4>
<hr />
<div class="row">
  <div class="col-md-4">
    <form asp-action="Create">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
      <div class="form-group">
        <label asp-for="ID" class="control-label"></label>
        <input asp-for="ID" class="form-control" />
        <span asp-validation-for="ID" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="Name" class="control-label"></label>
        <input asp-for="Name" class="form-control" />
        <span asp-validation-for="Name" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="Password" class="control-label"></label>
        <input asp-for="Password" class="form-control" type="password" /> <!-- type="password" 追加 -->
        <span asp-validation-for="Password" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="Age" class="control-label"></label>
        <input asp-for="Age" class="form-control" />
        <span asp-validation-for="Age" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="Email" class="control-label"></label>
        <input asp-for="Email" class="form-control" />
        <span asp-validation-for="Email" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="Birthday" class="control-label"></label>
        <input asp-for="Birthday" class="form-control" type="date" /> <!-- type="date" 追加 -->
        <span asp-validation-for="Birthday" class="text-danger"></span>
      </div>
      @* 更新日時は入力しないのでコメントアウト *@
      @*
      <div class="form-group">
        <label asp-for="UpdateDateTime" class="control-label"></label>
        <input asp-for="UpdateDateTime" class="form-control "/>
        <span asp-validation-for="UpdateDateTime" class="text-danger"></span>
      </div>
      *@
      <div class="form-group">
        <input type="submit" value="Create" class="btn btn-primary" />
      </div>
    </form>
  </div>
</div>

<div>
    <a asp-action="List">Back to List</a>  <!-- List に遷移するように変更 -->
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Run and confirm. By the way, there are no security measures such as password registration, so please follow ASP.NET Core and database registration methods when operating.

Of course, it is reflected in the database.

This Tips does not create edits or deletions, so you can use edit to the right | Details | Delete" also causes an error. You can create it in the same way as Create, so give it a try. The above three processes have also been added to the sample code.

Get database context from RequestServices

Adding di to a controller constructor can be a bit cumbersome because you have to add it to all the controllers you need. Alternatively, RequestServices you can get from .

It is not included in the sample code, but it can be obtained as follows.

/// <summary>
/// ユーザー一覧表示アクション。
/// </summary>
public IActionResult List()
{
  // RequestServices からデータベースコンテキストを取得する
  var dbContext = (TestDatabaseDbContext)HttpContext.RequestServices.GetService(typeof(TestDatabaseDbContext));
  
  // データベースから User 一覧を取得する
  var users = dbContext.Users.ToList();
  
  // ビューに渡す
  return View(users);
}

Create a database context directly

It is also used in consoles and desktop apps. You can use this method without any problems. It is not recommended because the scope of transactions tends to be ambiguous in Web applications where simultaneous access is likely to occur. In particular, updates may not be able to be rolled back to a request-by-request basis.

If you access the database in this way, DbContext you will use a technique to derive .

First, Startup modify the to work with Configuration static .

public class Startup
{
  public Startup(IConfiguration configuration)
  {
    Configuration = configuration;
    ConfigurationStatic = configuration;  // 追加
  }
  
  public IConfiguration Configuration { get; }
  public static IConfiguration ConfigurationStatic { get; private set; }  // 追加

  // 省略
}

TestDatabaseDbContext Create a class TestDatabaseDbContextEx derived from and set the appsettings.json connection string. If you can set a connection string, you can take another method, such as passing it through a constructor.

using Microsoft.Extensions.Configuration;
using Microsoft.EntityFrameworkCore;

namespace DatabaseEntityFrameworkCoreMvc.Models.Database
{
  public partial class TestDatabaseDbContextEx : TestDatabaseDbContext
  {
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      if (!optionsBuilder.IsConfigured)
      {
        optionsBuilder.UseSqlServer(Startup.ConfigurationStatic.GetConnectionString("TestDatabaseDbContext"));
      }
    }
  }
}

If you want to access the database, generate and use instances of the derived classes.

/// <summary>
/// ユーザー一覧表示アクション。
/// </summary>
public IActionResult List()
{
  // 派生クラスのデータベースコンテキストのインスタンスを生成する
  using var dbContext = new TestDatabaseDbContextEx();
  
  // データベースから User 一覧を取得する
  var users = dbContext.Users.ToList();
  
  // ビューに渡す
  return View(users);
}

ASP.NET example on a Core Razor page

ASP.NET several ways to use Entity Framework Core on a Core Razor page.

Add di (dependency insert) to the page model

By registering .cs services.AddDbContext method in startup.cs TestDatabaseDbContext It can be inserted into a page model.

An example of DI IndexModel is that the constructor has an ILogger<IndexModel> logger argument. This is added by DI. You can insert TestDatabaseDbContext in the same way.

If you IndexModel want to add to an existing , it looks like this: Of course, it can be added to other page models.

using DatabaseEntityFrameworkCoreMvc.Models.Database;  // 追加

// 省略

public class IndexModel : PageModel
{
  private readonly ILogger<IndexModel> _logger;
  
  // 追加
  private readonly TestDatabaseDbContext _dbContext;
  
  public IndexModel(ILogger<IndexModel> logger, TestDatabaseDbContext dbContext)  // 追加
  {
    _logger = logger;
    _dbContext = dbContext;  // 追加
  }
  
  // 省略
}

You can then access the database by using the instance of the context you received in each process.

Use cases

The following code is the code that handles user listing and new registrations. Both ASP.NET Core and Entity Framework Core will be code, so I won't go into details. Also, the context is automatically discarded when the user's request is over.

Create a page model for the list screen.

List.cshtml.cs as follows:

using System.Collections.Generic;
using System.Linq;
using DatabaseEntityFrameworkCoreRazor.Models.Database;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace DatabaseEntityFrameworkCoreRazor.Pages
{
  public class ListModel : PageModel
  {
    private readonly TestDatabaseDbContext _dbContext;
    
    /// <summary>
    /// 一覧に表示するためのユーザー一覧を格納します。
    /// </summary>
    public List<User> Users { get; set; }
    
    /// <summary>
    /// DI で TestDatabaseDbContext を受け取ります。
    /// </summary>
    /// <param name="dbContext"></param>
    public ListModel(TestDatabaseDbContext dbContext)
    {
      _dbContext = dbContext;
    }
    
    /// <summary>
    /// ページにアクセスされたときに呼ばれます。
    /// </summary>
    public void OnGet()
    {
      // データベースからユーザー一覧を取得します。
      Users = _dbContext.Users.ToList();
    }
  }
}

List.cshtml is created as follows:

@page
@model DatabaseEntityFrameworkCoreRazor.Pages.ListModel
@{
}

<h1>List</h1>

<p>
  <a asp-page="Create">Create New</a>
</p>
<table class="table">
  <thead>
    <tr>
      <th>
        @Html.DisplayNameFor(model => model.Users[0].ID)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Users[0].Name)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Users[0].Password)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Users[0].Age)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Users[0].Email)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Users[0].Birthday)
      </th>
      <th>
        @Html.DisplayNameFor(model => model.Users[0].UpdateDateTime)
      </th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    @foreach (var item in Model.Users)
    {
      <tr>
        <td>
          @Html.DisplayFor(modelItem => item.ID)
        </td>
        <td>
          @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
          @Html.DisplayFor(modelItem => item.Password)
        </td>
        <td>
          @Html.DisplayFor(modelItem => item.Age)
        </td>
        <td>
          @Html.DisplayFor(modelItem => item.Email)
        </td>
        <td>
          @Html.DisplayFor(modelItem => item.Birthday)
        </td>
        <td>
          @Html.DisplayFor(modelItem => item.UpdateDateTime)
        </td>
        <td>
          <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
          <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
          <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
        </td>
      </tr>
    }
  </tbody>
</table>

Add it to Index.cshtml so that you can transition to the List page.

<!-- 追加 -->
<ul>
  <li><a asp-page="List">List</a></li>
</ul>

Create a user registration screen as well.

Create.cshtml.cs code as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using DatabaseEntityFrameworkCoreRazor.Models.Database;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace DatabaseEntityFrameworkCoreRazor.Pages
{
  public class CreateModel : PageModel
  {
    private readonly TestDatabaseDbContext _dbContext;

    /// <summary>
    /// 登録するユーザー情報を格納します。
    /// </summary>
    [BindProperty]
    public User UserInfo { get; set; }

    /// <summary>
    /// DI で TestDatabaseDbContext を受け取ります。
    /// </summary>
    /// <param name="dbContext"></param>
    public CreateModel(TestDatabaseDbContext dbContext)
    {
      _dbContext = dbContext;
    }

    /// <summary>
    /// ページにアクセスされたときに呼ばれます。
    /// </summary>
    public void OnGet()
    {
      // 画面表示時は何もしません。
    }

    /// <summary>
    /// POST が送信されたときに呼ばれる。
    /// </summary>
    public IActionResult OnPost()
    {
      // エラーがある場合は登録画面に戻る
      if (ModelState.IsValid == false) return Page();

      // 更新日時設定
      UserInfo.UpdateDateTime = DateTime.Now;

      // 登録リストにユーザー追加
      _dbContext.Users.Add(UserInfo);

      // 登録を確定する
      _dbContext.SaveChanges();

      // 一覧画面に遷移
      return RedirectToPage("List");
    }
  }
}

Create.cshtml as follows:

@page
@model DatabaseEntityFrameworkCoreRazor.Pages.CreateModel
@{
}

<h1>Create</h1>

<h4>User</h4>
<hr />
<div class="row">
  <div class="col-md-4">
    <form asp-action="Create">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
      <div class="form-group">
        <label asp-for="UserInfo.ID" class="control-label"></label>
        <input asp-for="UserInfo.ID" class="form-control" />
        <span asp-validation-for="UserInfo.ID" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="UserInfo.Name" class="control-label"></label>
        <input asp-for="UserInfo.Name" class="form-control" />
        <span asp-validation-for="UserInfo.Name" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="UserInfo.Password" class="control-label"></label>
        <input asp-for="UserInfo.Password" class="form-control" type="password" />
        <span asp-validation-for="UserInfo.Password" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="UserInfo.Age" class="control-label"></label>
        <input asp-for="UserInfo.Age" class="form-control" />
        <span asp-validation-for="UserInfo.Age" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="UserInfo.Email" class="control-label"></label>
        <input asp-for="UserInfo.Email" class="form-control" />
        <span asp-validation-for="UserInfo.Email" class="text-danger"></span>
      </div>
      <div class="form-group">
        <label asp-for="UserInfo.Birthday" class="control-label"></label>
        <input asp-for="UserInfo.Birthday" class="form-control" type="date" />
        <span asp-validation-for="UserInfo.Birthday" class="text-danger"></span>
      </div>
      @*
        <div class="form-group">
          <label asp-for="UpdateDateTime" class="control-label"></label>
          <input asp-for="UpdateDateTime" class="form-control" />
          <span asp-validation-for="UpdateDateTime" class="text-danger"></span>
        </div>
      *@
      <div class="form-group">
        <input type="submit" value="Create" class="btn btn-primary" />
      </div>
    </form>
  </div>
</div>

<div>
  <a asp-page="List">Back to List</a>
</div>

Run and confirm. By the way, there are no security measures such as password registration, so please follow ASP.NET Core and database registration methods when operating.

Of course, it is reflected in the database.

I didn't create any edits or deletions, so I don't want edit to | Details | Delete" also causes an error. You can create it in the same way as Create, so give it a try. The above three processes have also been added to the sample code.

Get database context from RequestServices

Adding di to a page model constructor is a bit cumbersome because you have to add it to all the page models you need. Alternatively, RequestServices you can get from .

It is not included in the sample code, but it can be obtained as follows.

/// <summary>
/// ページにアクセスされたときに呼ばれます。
/// </summary>
public void OnGet()
{
  // RequestServices からデータベースコンテキストを取得する
  var dbContext = (TestDatabaseDbContext)HttpContext.RequestServices.GetService(typeof(TestDatabaseDbContext));
  
  // データベースからユーザー一覧を取得します。
  Users = dbContext.Users.ToList();
}

Create a database context directly

It is also used in consoles and desktop apps. You can use this method without any problems. It is not recommended because the scope of transactions tends to be ambiguous in Web applications where simultaneous access is likely to occur. In particular, updates may not be able to be rolled back to a request-by-request basis.

If you access the database in this way, DbContext you will use a technique to derive .

First, Startup modify the to work with Configuration static .

public class Startup
{
  public Startup(IConfiguration configuration)
  {
    Configuration = configuration;
    ConfigurationStatic = configuration;  // 追加
  }
  
  public IConfiguration Configuration { get; }
  public static IConfiguration ConfigurationStatic { get; private set; }  // 追加

  // 省略
}

TestDatabaseDbContext Create a class TestDatabaseDbContextEx derived from and set the appsettings.json connection string. If you can set a connection string, you can take another method, such as passing it through a constructor.

using Microsoft.Extensions.Configuration;
using Microsoft.EntityFrameworkCore;

namespace DatabaseEntityFrameworkCoreRazor.Models.Database
{
  public partial class TestDatabaseDbContextEx : TestDatabaseDbContext
  {
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
      if (!optionsBuilder.IsConfigured)
      {
        optionsBuilder.UseSqlServer(Startup.ConfigurationStatic.GetConnectionString("TestDatabaseDbContext"));
      }
    }
  }
}

If you want to access the database, generate and use instances of the derived classes.

/// <summary>
/// ページにアクセスされたときに呼ばれます。
/// </summary>
public void OnGet()
{
  // 派生クラスのデータベースコンテキストのインスタンスを生成する
  using var dbContext = new TestDatabaseDbContextEx();
    
  // データベースからユーザー一覧を取得します。
  Users = dbContext.Users.ToList();
}