ASP.NET Core での Entity Framework Core を使用した Razor ページ - チュートリアル 1/8Razor Pages with Entity Framework Core in ASP.NET Core - Tutorial 1 of 8

このチュートリアルの ASP.NET Core 2.0 バージョンについては、この PDF ファイルを参照してください。The ASP.NET Core 2.0 version of this tutorial can be found in this PDF file.

このチュートリアルの ASP.NET Core 2.1 バージョンでは、バージョン 2.0 から多くの機能が強化されています。The ASP.NET Core 2.1 version of this tutorial has many improvements over the 2.0 version.

作成者: Tom DykstraRick AndersonBy Tom Dykstra and Rick Anderson

Contoso University のサンプル Web アプリでは、Entity Framework (EF) Core を使用して ASP.NET Core Razor Pages アプリを作成する方法を示しています。The Contoso University sample web app demonstrates how to create an ASP.NET Core Razor Pages app using Entity Framework (EF) Core.

このサンプル アプリは架空の Contoso University の Web サイトです。The sample app is a web site for a fictional Contoso University. 学生の受け付け、講座の作成、講師の割り当てなどの機能が含まれています。It includes functionality such as student admission, course creation, and instructor assignments. このページは、Contoso University のサンプル アプリを作成する方法を説明するチュートリアル シリーズの 1 回目です。This page is the first in a series of tutorials that explain how to build the Contoso University sample app.

完成したアプリをダウンロードまたは表示します。Download or view the completed app. ダウンロードの方法はこちらをご覧ください。Download instructions.

必須コンポーネントPrerequisites

以下のワークロードで Visual Studio 2017 バージョン 15.7.3 以降:Visual Studio 2017 version 15.7.3 or later with the following workloads:

  • ASP.NET と Web 開発ASP.NET and web development
  • .NET Core クロスプラットフォームの開発.NET Core cross-platform development

Razor ページに関する知識。Familiarity with Razor Pages. Razor ページのプログラミングが初めての場合、このシリーズを始める前にこちらの入門編を完了してください。New programmers should complete Get started with Razor Pages before starting this series.

トラブルシューティングTroubleshooting

解決できない問題に遭遇した場合、通常、完成済みのプロジェクトと自分のコードを比較することで解決策がわかります。If you run into a problem you can't resolve, you can generally find the solution by comparing your code to the completed project. ヘルプが必要なときは、StackOverflow.comASP.NET Core または EF Core について質問を投稿することをお勧めします。A good way to get help is by posting a question to StackOverflow.com for ASP.NET Core or EF Core.

Contoso University Web アプリThe Contoso University web app

このチュートリアル シリーズで作成するアプリは、大学向けの基本的な Web サイトです。The app built in these tutorials is a basic university web site.

ユーザーは学生、講座、講師の情報を見たり、更新したりできます。Users can view and update student, course, and instructor information. チュートリアルで作成する画面は次のようになります。Here are a few of the screens created in the tutorial.

Students インデックス ページ

Students 編集ページ

このサイトの UI スタイルは、組み込みのテンプレートによって生成されるものに類似しています。The UI style of this site is close to what's generated by the built-in templates. このチュートリアルでは、UI ではなく、EF Core と Razor ページに重点を置きます。The tutorial focus is on EF Core with Razor Pages, not the UI.

ContosoUniversity Razor Pages Web アプリを作成するCreate the ContosoUniversity Razor Pages web app

  • Visual Studio の [ファイル] メニューから、[新規作成]、>[プロジェクト] の順に選択します。From the Visual Studio File menu, select New > Project.
  • 新しい ASP.NET Core Web アプリケーションを作成します。Create a new ASP.NET Core Web Application. プロジェクトに ContosoUniversity という名前を付けます。Name the project ContosoUniversity. このプロジェクトに ContosoUniversity という名前を付けることは重要です。そうすることでコードをコピーしたり貼り付けるときに名前空間が一致します。It's important to name the project ContosoUniversity so the namespaces match when code is copy/pasted.
  • ドロップダウン リストで [ASP.NET Core 2.1] を選択してから、[Web アプリケーション] を選択します。Select ASP.NET Core 2.1 in the dropdown, and then select Web Application.

前の手順の画像については、「Razor Web アプリの作成」を参照してください。For images of the preceding steps, see Create a Razor web app. アプリを実行します。Run the app.

サイトのスタイルを設定するSet up the site style

変更をいくつか行い、サイトのメニュー、レイアウト、ホーム ページを決めます。A few changes set up the site menu, layout, and home page. Pages/Shared/_Layout.cshtml に次の変更を加えます。Update Pages/Shared/_Layout.cshtml with the following changes:

  • "ContosoUniversity" をすべて "Contoso University" に変更します。Change each occurrence of "ContosoUniversity" to "Contoso University". これは 3 回出てきます。There are three occurrences.

  • メニュー エントリとして「Students」、「Courses」、「Instructors」、「Departments」を追加し、「Contact」を削除します。Add menu entries for Students, Courses, Instructors, and Departments, and delete the Contact menu entry.

変更が強調表示されます。The changes are highlighted. (マークアップは一部表示されていません。)(All the markup is not displayed.)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] : Contoso University</title>

    <environment include="Development">
        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
    </environment>
    <environment exclude="Development">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>
</head>
<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a asp-page="/Index" class="navbar-brand">Contoso University</a>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a asp-page="/Index">Home</a></li>
                    <li><a asp-page="/About">About</a></li>
                    <li><a asp-page="/Students/Index">Students</a></li>
                    <li><a asp-page="/Courses/Index">Courses</a></li>
                    <li><a asp-page="/Instructors/Index">Instructors</a></li>
                    <li><a asp-page="/Departments/Index">Departments</a></li>
                </ul>
            </div>
        </div>
    </nav>

    <partial name="_CookieConsentPartial" />

    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; 2018 : Contoso University</p>
        </footer>
    </div>

    @*Remaining markup not shown for brevity.*@

Pages/Index.cshtml で、ファイルの中身を次のコードに変更し、ASP.NET と MVC に関するテキストをこのアプリに関するテキストに変更します。In Pages/Index.cshtml, replace the contents of the file with the following code to replace the text about ASP.NET and MVC with text about this app:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="jumbotron">
    <h1>Contoso University</h1>
</div>
<div class="row">
    <div class="col-md-4">
        <h2>Welcome to Contoso University</h2>
        <p>
            Contoso University is a sample application that
            demonstrates how to use Entity Framework Core in an
            ASP.NET Core Razor Pages web app.
        </p>
    </div>
    <div class="col-md-4">
        <h2>Build it from scratch</h2>
        <p>You can build the application by following the steps in a series of tutorials.</p>
        <p>
            <a class="btn btn-default"
               href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro">
                See the tutorial &raquo;
            </a>
        </p>
    </div>
    <div class="col-md-4">
        <h2>Download it</h2>
        <p>You can download the completed project from GitHub.</p>
        <p>
            <a class="btn btn-default"
               href="https://github.com/aspnet/Docs/tree/master/aspnetcore/data/ef-rp/intro/samples/cu-final">
                See project source code &raquo;
            </a>
        </p>
    </div>
</div>

データ モデルを作成するCreate the data model

Contoso University アプリのエンティティ クラスを作成します。Create entity classes for the Contoso University app. 次の 3 つのエンティティから始めます。Start with the following three entities:

Course、Enrollment、Student からなるデータ モデルの図

Student エンティティと Enrollment エンティティの間には一対多の関係があります。There's a one-to-many relationship between Student and Enrollment entities. Course エンティティと Enrollment エンティティの間には一対多の関係があります。There's a one-to-many relationship between Course and Enrollment entities. 1 人の学生をさまざまな講座に登録できます。A student can enroll in any number of courses. 1 つの講座に任意の数の学生を登録できます。A course can have any number of students enrolled in it.

次のセクションでは、エンティティごとにクラスを作成します。In the following sections, a class for each one of these entities is created.

Student エンティティThe Student entity

Student エンティティの図

Models フォルダーを作成します。Create a Models folder. 以下のコードを使用して、Models フォルダーで、Student.cs という名前のクラス ファイルを作成します。In the Models folder, create a class file named Student.cs with the following code:

using System;
using System.Collections.Generic;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

ID プロパティは、このクラスに相当するデータベース (DB) テーブルの主キー列になります。The ID property becomes the primary key column of the database (DB) table that corresponds to this class. 既定では、EF Core は、ID または classnameID という名前のプロパティを主キーとして解釈します。By default, EF Core interprets a property that's named ID or classnameID as the primary key. classnameIDclassname はクラスの名前です。In classnameID, classname is the name of the class. 代わりの自動的に認識される主キーは、前の例の StudentID です。The alternative automatically recognized primary key is StudentID in the preceding example.

Enrollments プロパティはナビゲーション プロパティです。The Enrollments property is a navigation property. ナビゲーション プロパティは、このエンティティに関連する他のエンティティにリンクします。Navigation properties link to other entities that are related to this entity. この例では、Student entityEnrollments プロパティによって、その Student に関連するすべての Enrollment エンティティが保持されます。In this case, the Enrollments property of a Student entity holds all of the Enrollment entities that are related to that Student. たとえば、DB 内のある Student 行に 2 つ関連する Enrollment 行がある場合、Enrollments ナビゲーション プロパティにその 2 つの Enrollment エンティティが含まれます。For example, if a Student row in the DB has two related Enrollment rows, the Enrollments navigation property contains those two Enrollment entities. 関連する Enrollment 行とは、その学生の主キー値を StudentID 列に含む行です。A related Enrollment row is a row that contains that student's primary key value in the StudentID column. たとえば、ID=1 の学生には、Enrollment テーブルに行が 2 つあるとします。For example, suppose the student with ID=1 has two rows in the Enrollment table. その Enrollment テーブルには、StudentID = 1 の行が 2 つあります。The Enrollment table has two rows with StudentID = 1. StudentIDEnrollment テーブルの外部キーであり、Student テーブルでその学生を指定します。StudentID is a foreign key in the Enrollment table that specifies the student in the Student table.

あるナビゲーション プロパティが複数のエンティティを保持できる場合、そのナビゲーション プロパティは ICollection<T> のようなリスト型にする必要があります。If a navigation property can hold multiple entities, the navigation property must be a list type, such as ICollection<T>. ICollection<T> を指定するか、List<T>HashSet<T> のような型を指定できます。ICollection<T> can be specified, or a type such as List<T> or HashSet<T>. ICollection<T> を使用する場合、EF Core で HashSet<T> コレクションが既定で作成されます。When ICollection<T> is used, EF Core creates a HashSet<T> collection by default. 複数のエンティティを保持するナビゲーション プロパティは、多対多または一対多の関係から発生します。Navigation properties that hold multiple entities come from many-to-many and one-to-many relationships.

Enrollment エンティティThe Enrollment entity

Enrollment エンティティの図

以下のコードを使用して、Models フォルダーで、Enrollment.cs を作成します。In the Models folder, create Enrollment.cs with the following code:

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}

EnrollmentID プロパティは主キーです。The EnrollmentID property is the primary key. このエンティティでは、Student エンティティのような ID ではなく、classnameID パターンを使用します。This entity uses the classnameID pattern instead of ID like the Student entity. 一般的に、開発者は 1 つのパターンを選択し、データ モデル全体でそれを使用します。Typically developers choose one pattern and use it throughout the data model. 後のチュートリアルでは、クラス名なしの ID を利用し、データ モデルに継承を簡単に実装します。In a later tutorial, using ID without classname is shown to make it easier to implement inheritance in the data model.

Grade プロパティは enum です。The Grade property is an enum. Grade の型宣言の後の疑問符は、Grade プロパティが null 許容であることを示します。The question mark after the Grade type declaration indicates that the Grade property is nullable. null という成績は、0 の成績とは異なります。null は成績がわからないことか、まだ評価されていないことを意味します。A grade that's null is different from a zero grade -- null means a grade isn't known or hasn't been assigned yet.

StudentID プロパティは外部キーです。それに対応するナビゲーション プロパティは Student です。The StudentID property is a foreign key, and the corresponding navigation property is Student. Enrollment エンティティは 1 つの Studentエンティティに関連付けられますので、このプロパティには Student エンティティが 1 つ含まれます。An Enrollment entity is associated with one Student entity, so the property contains a single Student entity. Student エンティティは、複数の Enrollment エンティティが含まれる Student.Enrollments ナビゲーション プロパティとは異なります。The Student entity differs from the Student.Enrollments navigation property, which contains multiple Enrollment entities.

CourseID プロパティは外部キーです。それに対応するナビゲーション プロパティは Course です。The CourseID property is a foreign key, and the corresponding navigation property is Course. Enrollment エンティティは 1 つの Course エンティティに関連付けられます。An Enrollment entity is associated with one Course entity.

EF Core は、プロパティの名前が <navigation property name><primary key property name> であれば、それを外部キーとして解釈します。EF Core interprets a property as a foreign key if it's named <navigation property name><primary key property name>. たとえば、Student ナビゲーション プロパティの StudentID です。Student エンティティの主キーは ID であるからです。For example,StudentID for the Student navigation property, since the Student entity's primary key is ID. 外部キーのプロパティには <primary key property name> という名前を付けることもできます。Foreign key properties can also be named <primary key property name>. たとえば、CourseID にします。Course エンティティの主キーが CourseID であるからです。For example, CourseID since the Course entity's primary key is CourseID.

Course エンティティThe Course entity

Course エンティティの図

以下のコードを使用して、Models フォルダーで、Course.cs を作成します。In the Models folder, create Course.cs with the following code:

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CourseID { get; set; }
        public string Title { get; set; }
        public int Credits { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

Enrollments プロパティはナビゲーション プロパティです。The Enrollments property is a navigation property. 1 つの Course エンティティにたくさんの Enrollment エンティティを関連付けることができます。A Course entity can be related to any number of Enrollment entities.

DatabaseGenerated 属性によって、アプリで主キーを指定できます。DB に生成させるのではありません。The DatabaseGenerated attribute allows the app to specify the primary key rather than having the DB generate it.

Student モデルをスキャホールディングするScaffold the student model

このセクションでは、Student モデルがスキャフォールディングされます。In this section, the student model is scaffolded. つまり、スキャフォールディング ツールにより、Student モデルの作成、読み取り、更新、削除の (CRUD) 操作用のページが生成されます。That is, the scaffolding tool produces pages for Create, Read, Update, and Delete (CRUD) operations for the student model.

  • プロジェクトをビルドします。Build the project.
  • Pages/Students フォルダーを作成します。Create the Pages/Students folder.
  • ソリューション エクスプローラーで、[Pages/Students] フォルダーを右クリックし、[追加] > [スキャフォールディングされた新しい項目] の順に選択します。In Solution Explorer, right click on the Pages/Students folder > Add > New Scaffolded Item.
  • [スキャフォールディングを追加] ダイアログで、[Razor Pages using Entity Framework (CRUD)](Entity Framework を使用する Razor Pages (CRUD)) > [追加] の順に選択します。In the Add Scaffold dialog, select Razor Pages using Entity Framework (CRUD) > ADD.

[Add Razor Pages using Entity Framework (CRUD)](Entity Framework を使用して Razor Pages (CRUD) を追加する) ダイアログを完了します。Complete the Add Razor Pages using Entity Framework (CRUD) dialog:

  • [モデル クラス] ドロップダウンで、[Student (ContosoUniversity.Models)] を選択します。In the Model class drop-down, select Student (ContosoUniversity.Models).
  • [データ コンテキスト クラス] 行で + (+) 記号を選択し、生成された名前を ContosoUniversity.Models.SchoolContext に変更します。In the Data context class row, select the + (plus) sign and change the generated name to ContosoUniversity.Models.SchoolContext.
  • [データ コンテキスト クラス] ドロップダウンで、[ContosoUniversity.Models.SchoolContext] を選択します。In the Data context class drop-down, select ContosoUniversity.Models.SchoolContext
  • [追加] を選びます。Select Add.

CRUD ダイアログ

前の手順に問題がある場合は、「ムービー モデルのスキャフォールディング」を参照してください。See Scaffold the movie model if you have a problem with the preceding step.

スキャフォールディングのプロセスが作成され、次のファイルが変更されます。The scaffold process created and changed the following files:

作成されたファイルFiles created

  • Pages/Students 作成、削除、詳細、編集、インデックス。Pages/Students Create, Delete, Details, Edit, Index.
  • Data/SchoolContext.csData/SchoolContext.cs

ファイルの更新File updates

  • Startup.cs: このファイルに対しての変更を次のセクションで詳しく説明します。Startup.cs : Changes to this file are detailed in the next section.
  • appsettings.json: ローカル データベースへの接続に使用される接続文字列を追加します。appsettings.json : The connection string used to connect to a local database is added.

依存関係挿入に登録されるコンテキストを調べるExamine the context registered with dependency injection

ASP.NET Core には、依存関係挿入が組み込まれています。ASP.NET Core is built with dependency injection. サービス (EF Core DB コンテキストなど) は、アプリケーションの起動時に依存関係挿入に登録されます。Services (such as the EF Core DB context) are registered with dependency injection during application startup. これらのサービスを必要とするコンポーネント (Razor ページなど) には、コンストラクターのパラメーターを介してこれらのサービスが指定されます。Components that require these services (such as Razor Pages) are provided these services via constructor parameters. db コンテキスト インスタンスを取得するコンストラクター コードは、チュートリアルの後半で示します。The constructor code that gets a db context instance is shown later in the tutorial.

スキャフォールディング ツールが自動的に DB コンテキストを作成し、依存関係挿入コンテナーと共に登録します。The scaffolding tool automatically created a DB Context and registered it with the dependency injection container.

Startup.csConfigureServices メソッドを調べます。Examine the ConfigureServices method in Startup.cs. 強調表示された行は、スキャフォールダーによって追加されました。The highlighted line was added by the scaffolder:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for 
        //non -essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddDbContext<SchoolContext>(options =>
       options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
}

DbContextOptions オブジェクトでメソッドが呼び出され、接続文字列の名前がコンテキストに渡されます。The name of the connection string is passed in to the context by calling a method on a DbContextOptions object. ローカル開発の場合、ASP.NET Core 構成システムappsettings.json ファイルから接続文字列を読み取ります。For local development, the ASP.NET Core configuration system reads the connection string from the appsettings.json file.

main を更新するUpdate main

Program.cs で、次を実行するように Main メソッドを変更します。In Program.cs, modify the Main method to do the following:

  • 依存関係挿入コンテナーから DB コンテキスト インスタンスを取得します。Get a DB context instance from the dependency injection container.
  • EnsureCreated を呼び出します。Call the EnsureCreated.
  • EnsureCreated メソッドが完了したら、コンテキストを破棄します。Dispose the context when the EnsureCreated method completes.

次は、更新された Program.cs ファイルのコードです。The following code shows the updated Program.cs file.

using ContosoUniversity.Models;                   // SchoolContext
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;   // CreateScope
using Microsoft.Extensions.Logging;
using System;

namespace ContosoUniversity
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

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

                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    context.Database.EnsureCreated();
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }

            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

EnsureCreated で、コンテキストのデータベースが存在することを確認します。EnsureCreated ensures that the database for the context exists. 存在する場合、アクションは何も実行されません。If it exists, no action is taken. 存在しない場合は、データベースとそのすべてのスキーマが作成されます。If it does not exist, then the database and all its schema are created. EnsureCreated は、データベースの作成に移行を使用しません。EnsureCreated does not use migrations to create the database. EnsureCreated で作成されたデータベースは、後で移行を使用して更新することはできません。A database that is created with EnsureCreated cannot be later updated using migrations.

アプリの起動時に EnsureCreated が呼び出され、次のワークフローが可能になります。EnsureCreated is called on app start, which allows the following work flow:

  • DB を削除します。Delete the DB.
  • DB スキーマを変更します (たとえば、EmailAddress フィールドを追加します)。Change the DB schema (for example, add an EmailAddress field).
  • アプリを実行します。Run the app.
  • EnsureCreated によって、EmailAddress 列を含む DB が作成されます。EnsureCreated creates a DB with theEmailAddress column.

EnsureCreated は、スキーマが急速に進化している開発の早期に便利です。EnsureCreated is convenient early in development when the schema is rapidly evolving. このチュートリアルの後半では、DB は削除され、移行が使用されます。Later in the tutorial the DB is deleted and migrations are used.

アプリのテストTest the app

アプリを実行し、Cookie ポリシーに同意します。Run the app and accept the cookie policy. このアプリで個人情報が保持されることはありません。This app doesn't keep personal information. Cookie ポリシーについては、EU の一般的なデータ保護規制 (GDPR) のサポートに関するページを参照してください。You can read about the cookie policy at EU General Data Protection Regulation (GDPR) support.

  • [Students] リンクを選択し、[新規作成] を選択します。Select the Students link and then Create New.
  • [編集]、[詳細]、および [削除] の各リンクをテストします。Test the Edit, Details, and Delete links.

SchoolContext DB コンテキストを確認するExamine the SchoolContext DB context

所与のデータ モデルの EF Core 機能を調整するメイン クラスは、DB コンテキスト クラスです。The main class that coordinates EF Core functionality for a given data model is the DB context class. データ コンテキストは Microsoft.EntityFrameworkCore.DbContext から派生されます。The data context is derived from Microsoft.EntityFrameworkCore.DbContext. データ コンテキストによって、データ モデルに含めるエンティティが指定されます。The data context specifies which entities are included in the data model. このプロジェクトでは、クラスに SchoolContext という名前が付けられています。In this project, the class is named SchoolContext.

次のコードを使用して SchoolContext.cs を更新します。Update SchoolContext.cs with the following code:

using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Models
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options)
            : base(options)
        {
        }

        public DbSet<Student> Student { get; set; }
        public DbSet<Enrollment> Enrollment { get; set; }
        public DbSet<Course> Course { get; set; }
    }
}

強調表示されたコードで、各エンティティ セットの DbSet< TEntity> プロパティが作成されます。The highlighted code creates a DbSet<TEntity> property for each entity set. EF Core 用語で:In EF Core terminology:

  • エンティティ セットは通常、DB テーブルに対応します。An entity set typically corresponds to a DB table.
  • エンティティはテーブル内の行に対応します。An entity corresponds to a row in the table.

DbSet<Enrollment>DbSet<Course> は省略可能です。DbSet<Enrollment> and DbSet<Course> could be omitted. EF Core にはそれらが暗黙的に含まれます。Student エンティティが Enrollment エンティティを参照し、Enrollment エンティティが Course エンティティを参照するためです。EF Core includes them implicitly because the Student entity references the Enrollment entity, and the Enrollment entity references the Course entity. このチュートリアルでは、SchoolContextDbSet<Enrollment>DbSet<Course> を残します。For this tutorial, keep DbSet<Enrollment> and DbSet<Course> in the SchoolContext.

SQL Server Express LocalDBSQL Server Express LocalDB

この接続文字列によって SQL Server LocalDB が指定されます。The connection string specifies SQL Server LocalDB. LocalDB は SQL Server Express データベース エンジンの軽量版であり、実稼働ではなく、アプリの開発を意図して設計されています。LocalDB is a lightweight version of the SQL Server Express Database Engine and is intended for app development, not production use. LocalDB は要求時に開始され、ユーザー モードで実行されるため、複雑な構成はありません。LocalDB starts on demand and runs in user mode, so there's no complex configuration. 既定では、LocalDB は C:/Users/<user> ディレクトリに .mdf DB ファイルを作成します。By default, LocalDB creates .mdf DB files in the C:/Users/<user> directory.

テスト データで DB を初期化するコードを追加するAdd code to initialize the DB with test data

EF Core によって空の DB が作成されます。EF Core creates an empty DB. このセクションでは、それにテスト データを入力するために Initialize メソッドを記述します。In this section, an Initialize method is written to populate it with test data.

Data フォルダーで、DbInitializer.cs という名前の新しいクラス ファイルを作成し、次のコードを追加します。In the Data folder, create a new class file named DbInitializer.cs and add the following code:

using ContosoUniversity.Models;
using System;
using System.Linq;

namespace ContosoUniversity.Models
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            // context.Database.EnsureCreated();

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

            var students = new Student[]
            {
            new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
            new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
            new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
            new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
            new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
            };
            foreach (Student s in students)
            {
                context.Student.Add(s);
            }
            context.SaveChanges();

            var courses = new Course[]
            {
            new Course{CourseID=1050,Title="Chemistry",Credits=3},
            new Course{CourseID=4022,Title="Microeconomics",Credits=3},
            new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
            new Course{CourseID=1045,Title="Calculus",Credits=4},
            new Course{CourseID=3141,Title="Trigonometry",Credits=4},
            new Course{CourseID=2021,Title="Composition",Credits=3},
            new Course{CourseID=2042,Title="Literature",Credits=4}
            };
            foreach (Course c in courses)
            {
                context.Course.Add(c);
            }
            context.SaveChanges();

            var enrollments = new Enrollment[]
            {
            new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
            new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
            new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
            new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
            new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
            new Enrollment{StudentID=3,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=1050},
            new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
            new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
            new Enrollment{StudentID=6,CourseID=1045},
            new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
            };
            foreach (Enrollment e in enrollments)
            {
                context.Enrollment.Add(e);
            }
            context.SaveChanges();
        }
    }
}

このコードは、DB に学生が存在するかどうかを確認します。The code checks if there are any students in the DB. DB に学生が存在しない場合、テスト データを使用して DB が初期化されます。If there are no students in the DB, the DB is initialized with test data. List<T> コレクションではなく配列にテスト データを読み込み、パフォーマンスを最適化します。It loads test data into arrays rather than List<T> collections to optimize performance.

EnsureCreated メソッドは、DB のコンテキストに合わせて DB を自動的に作成します。The EnsureCreated method automatically creates the DB for the DB context. DB が存在する場合、EnsureCreated は DB を変更することなく戻ってきます。If the DB exists, EnsureCreated returns without modifying the DB.

Program.cs で、Initialize を呼び出すように Main メソッドを変更します。In Program.cs, modify the Main method to call Initialize:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();

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

            try
            {
                var context = services.GetRequiredService<SchoolContext>();
                // using ContosoUniversity.Data; 
                DbInitializer.Initialize(context);
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred creating the DB.");
            }
        }

        host.Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

学生のレコードをすべて削除し、アプリを再起動します。Delete any student records and restart the app. DB が初期化されていない場合は、ブレーク ポイントを Initialize に設定して問題を診断します。If the DB is not initialized, set a break point in Initialize to diagnose the problem.

DB を表示するView the DB

Visual Studio の [表示] メニューから SQL Server オブジェクト エクスプローラー (SSOX) を開きます。Open SQL Server Object Explorer (SSOX) from the View menu in Visual Studio. SSOX で、(localdb)\MSSQLLocalDB > Databases > ContosoUniversity1 をクリックします。In SSOX, click (localdb)\MSSQLLocalDB > Databases > ContosoUniversity1.

[Tables](テーブル) ノードを展開します。Expand the Tables node.

[Student](学生) テーブルを右クリックし、[View Data](データの表示) をクリックすると、作成された列とテーブルに挿入された行が表示されます。Right-click the Student table and click View Data to see the columns created and the rows inserted into the table.

非同期コードAsynchronous code

ASP.NET Core と EF Core では、非同期プログラミングが既定のモードです。Asynchronous programming is the default mode for ASP.NET Core and EF Core.

Web サーバーでは、利用できるスレッド数に限りがあります。負荷が高い状況では、利用できるスレッドが全部使われる可能性があります。A web server has a limited number of threads available, and in high load situations all of the available threads might be in use. その場合、スレッドが解放されるまでサーバーは新しい要求を処理できません。When that happens, the server can't process new requests until the threads are freed up. 同期コードの場合、たくさんのスレッドが関連付けられていても、I/O の完了を待っているため、実際には何の作業も行っていないということがあります。With synchronous code, many threads may be tied up while they aren't actually doing any work because they're waiting for I/O to complete. 非同期コードの場合、あるプロセスが I/O の完了を待っているとき、そのスレッドは解放され、サーバーによって他の要求の処理に利用できます。With asynchronous code, when a process is waiting for I/O to complete, its thread is freed up for the server to use for processing other requests. 結果として、非同期コードの場合、サーバー リソースをより効率的に利用できます。サーバーは、より多くのトラフィックを遅延なく処理できます。As a result, asynchronous code enables server resources to be used more efficiently, and the server is enabled to handle more traffic without delays.

非同期コードが実行時に発生させるオーバーヘッドは少量です。Asynchronous code does introduce a small amount of overhead at run time. トラフィックが少ない場合、パフォーマンスに与える影響は無視して構わない程度です。トラフィックが多い場合、相当なパフォーマンス改善が見込まれます。For low traffic situations, the performance hit is negligible, while for high traffic situations, the potential performance improvement is substantial.

次のコードでは、キーワード async、戻り値 Task<T>、キーワード await、メソッド ToListAsync によりコードの実行が非同期になります。In the following code, the async keyword, Task<T> return value, await keyword, and ToListAsync method make the code execute asynchronously.

public async Task OnGetAsync()
{
    Student = await _context.Student.ToListAsync();
}
  • キーワード async は次のことをコンパイラに指示します。The async keyword tells the compiler to:

    • メソッド本文の一部にコールバックを生成する。Generate callbacks for parts of the method body.
    • 返された Task オブジェクトを自動作成する。Automatically create the Task object that's returned. 詳細については、Task の戻り値の型に関する記事を参照してください。For more information, see Task Return Type.
  • 暗黙の戻り値の型 Task は進行中の作業を表します。The implicit return type Task represents ongoing work.

  • キーワード await により、コンパイラはメソッドを 2 つに分割します。The await keyword causes the compiler to split the method into two parts. 最初の部分は、非同期で開始される操作で終わります。The first part ends with the operation that's started asynchronously. 2 つ目の部分は、操作の完了時に呼び出されるコールバック メソッドに入ります。The second part is put into a callback method that's called when the operation completes.

  • ToListAsync は、ToList 拡張メソッドの非同期バージョンです。ToListAsync is the asynchronous version of the ToList extension method.

EF Core を利用する非同期コードの記述で注意すべき点:Some things to be aware of when writing asynchronous code that uses EF Core:

  • クエリやコマンドを DB に送信するステートメントのみが非同期で実行されます。Only statements that cause queries or commands to be sent to the DB are executed asynchronously. これには、ToListAsyncSingleOrDefaultAsyncFirstOrDefaultAsyncSaveChangesAsync が含まれます。That includes, ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync, and SaveChangesAsync. var students = context.Students.Where(s => s.LastName == "Davolio") など、IQueryable を変更するだけのステートメントは含まれません。It doesn't include statements that just change an IQueryable, such as var students = context.Students.Where(s => s.LastName == "Davolio").
  • EF Core コンテキストはスレッド セーフではありません。複数の操作を並列実行しないでください。An EF Core context isn't thread safe: don't try to do multiple operations in parallel.
  • 非同期コードのパフォーマンス上の利点を最大限に活用するには、クエリをデータベースに送信させる EF Core メソッドを (ページングなどのための) ライブラリ パッケージで呼び出す場合、そのライブラリ パッケージで非同期が利用されていることを確認します。To take advantage of the performance benefits of async code, verify that library packages (such as for paging) use async if they call EF Core methods that send queries to the DB.

.NET での非同期プログラミングの詳細については、「非同期の概要」と「Async および Await を使用した非同期プログラミング (C#)」を参照してください。For more information about asynchronous programming in .NET, see Async Overview and Asynchronous programming with async and await.

次のチュートリアルでは、基本的な CRUD (作成、読み取り、更新、削除) の操作について説明します。In the next tutorial, basic CRUD (create, read, update, delete) operations are examined.