Razor Halaman dengan Entity Framework Core di ASP.NET Core - Tutorial 1 dari 8

Oleh Tom Dykstra, Jeremy Likness, dan Jon P Smith

Ini adalah yang pertama dalam serangkaian tutorial yang menunjukkan cara menggunakan Entity Framework (EF) Core di aplikasi ASP.NET Core Razor Pages . Tutorial ini membangun situs web untuk Universitas Contoso fiktif. Situs ini mencakup fungsionalitas seperti penerimaan siswa, pembuatan kursus, dan penugasan instruktur. Tutorial ini menggunakan pendekatan pertama kode. Untuk informasi tentang mengikuti tutorial ini menggunakan pendekatan pertama database, lihat masalah Github ini.

Unduh atau lihat aplikasi yang telah selesai.Unduh instruksi.

Prasyarat

Mesin database

Instruksi Visual Studio menggunakan SQL Server LocalDB, versi SQL Server Express yang hanya berjalan di Windows.

Pemecahan Masalah

Jika Anda mengalami masalah yang tidak dapat Anda atasi, bandingkan kode Anda dengan proyek yang telah selesai. Cara yang baik untuk mendapatkan bantuan adalah dengan memposting pertanyaan ke StackOverflow.com, menggunakan tag ASP.NET Core atau EF Core tag .

Aplikasi sampel

Aplikasi yang dibangun dalam tutorial ini adalah situs web universitas dasar. Pengguna dapat melihat dan memperbarui informasi siswa, kursus, dan instruktur. Berikut adalah beberapa layar yang dibuat dalam tutorial.

Students Index page

Students Edit page

Gaya UI situs ini didasarkan pada templat proyek bawaan. Fokus tutorial adalah pada cara menggunakan EF Core dengan ASP.NET Core, bukan cara menyesuaikan UI.

Opsional: Buat unduhan sampel

Langkah ini bersifat opsional. Membangun aplikasi yang telah selesai disarankan saat Anda memiliki masalah yang tidak dapat Anda selesaikan. Jika Anda mengalami masalah yang tidak dapat Anda atasi, bandingkan kode Anda dengan proyek yang telah selesai. Unduh instruksi.

Pilih ContosoUniversity.csproj untuk membuka proyek.

  • Bangun proyek.

  • Di Package Manager Console (PMC) jalankan perintah berikut:

    Update-Database
    

Jalankan proyek untuk menyemai database.

Membuat proyek aplikasi web

  1. Mulai Visual Studio 2022 dan pilih Buat proyek baru.

    Create a new project from the start window

  2. Dalam dialog Buat proyek baru, pilih ASP.NET Core Web App, lalu pilih Berikutnya.

    Create an ASP.NET Core Web App

  3. Dalam dialog Konfigurasikan proyek baru Anda, masukkan ContosoUniversity untuk Nama proyek. Penting untuk memberi nama proyek ContosoUniversity, termasuk mencocokkan kapitalisasi, sehingga namespace akan cocok saat Anda menyalin dan menempelkan kode contoh.

  4. Pilih Selanjutnya.

  5. Dalam dialog Informasi tambahan, pilih .NET 6.0 (Dukungan jangka panjang) lalu pilih Buat.

    Additional information

Menyiapkan gaya situs

Salin dan tempel kode berikut ke Pages/Shared/_Layout.cshtml dalam file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
    <link rel="stylesheet" href="~/ContosoUniversity.styles.css" asp-append-version="true" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">                        
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2021 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

File tata letak mengatur header situs, footer, dan menu. Kode sebelumnya membuat perubahan berikut:

  • Setiap kemunculan "ContosoUniversity" ke "Contoso University". Ada tiga kejadian.
  • Entri Home menu dan Privacy dihapus.
  • Entri ditambahkan untuk Tentang, Siswa, Kursus, Instruktur, dan Departemen.

Di Pages/Index.cshtml, ganti konten file dengan kode berikut:

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

<div class="row mb-auto">
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 mb-4 ">
                <p class="card-text">
                    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>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column position-static">
                <p class="card-text mb-auto">
                    You can build the application by following the steps in a series of tutorials.
                </p>
                <p>
@*                    <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
*@                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column">
                <p class="card-text mb-auto">
                    You can download the completed project from GitHub.
                </p>
                <p>
@*                    <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
*@                </p>
            </div>
        </div>
    </div>
</div>

Kode sebelumnya menggantikan teks tentang ASP.NET Core dengan teks tentang aplikasi ini.

Jalankan aplikasi untuk memverifikasi bahwa halaman beranda muncul.

Model data

Bagian berikut membuat model data:

Course-Enrollment-Student data model diagram

Siswa dapat mendaftar di sejumlah kursus, dan kursus dapat memiliki sejumlah siswa yang terdaftar di dalamnya.

Entitas Siswa

Student entity diagram

  • Buat folder Model di folder proyek.
  • Buat Models/Student.cs dengan kode berikut:
    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; }
        }
    }
    

Properti ID menjadi kolom kunci utama tabel database yang sesuai dengan kelas ini. Secara default, EF Core menginterpretasikan properti yang dinamai ID atau classnameID sebagai kunci utama. Jadi nama alternatif yang dikenali secara otomatis untuk Student kunci utama kelas adalah StudentID. Untuk informasi selengkapnya, lihat EF Core - Kunci.

Properti Enrollments adalah properti navigasi. Properti navigasi menyimpan entitas lain yang terkait dengan entitas ini. Dalam hal ini, Enrollments properti Student entitas memegang semua entitas yang terkait dengan Siswa tersebut Enrollment . Misalnya, jika baris Siswa dalam database memiliki dua baris Pendaftaran terkait, properti navigasi berisi dua entitas Pendaftaran tersebut Enrollments .

Dalam database, baris Pendaftaran terkait dengan baris Siswa jika kolomnya StudentID berisi nilai ID siswa. Misalnya, baris Siswa memiliki ID=1. Baris Pendaftaran terkait akan memiliki StudentID = 1. StudentID adalah kunci asing dalam tabel Pendaftaran.

Properti Enrollments didefinisikan sebagai ICollection<Enrollment> karena mungkin ada beberapa entitas Pendaftaran terkait. Jenis koleksi lain dapat digunakan, seperti List<Enrollment> atau HashSet<Enrollment>. Saat ICollection<Enrollment> digunakan, EF Core membuat HashSet<Enrollment> koleksi secara default.

Entitas Pendaftaran

Enrollment entity diagram

Buat Models/Enrollment.cs dengan kode berikut:

using System.ComponentModel.DataAnnotations;

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; }
        [DisplayFormat(NullDisplayText = "No grade")]
        public Grade? Grade { get; set; }

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

Properti EnrollmentID adalah kunci utama; entitas ini menggunakan pola alih-alih ID dengan sendirinyaclassnameID. Untuk model data produksi, banyak pengembang memilih satu pola dan menggunakannya secara konsisten. Tutorial ini menggunakan keduanya hanya untuk menggambarkan bahwa keduanya berfungsi. Menggunakan ID tanpa classname mempermudah penerapan beberapa jenis perubahan model data.

Properti Grade adalah enum. Tanda tanya setelah Grade deklarasi jenis menunjukkan bahwa Grade properti dapat diubah ke null. Nilai null berbeda dari nilai nol—null berarti nilai belum diketahui atau belum ditetapkan.

Properti StudentID adalah kunci asing, dan properti navigasi yang sesuai adalah Student. Entitas Enrollment dikaitkan dengan satu Student entitas, sehingga properti berisi satu Student entitas.

Properti CourseID adalah kunci asing, dan properti navigasi yang sesuai adalah Course. Entitas Enrollment dikaitkan dengan satu Course entitas.

EF Core menafsirkan properti sebagai kunci asing jika bernama <navigation property name><primary key property name>. Misalnya,StudentID adalah kunci asing untuk Student properti navigasi, karena Student kunci utama entitas adalah ID. Properti kunci asing juga dapat diberi nama <primary key property name>. Misalnya, CourseID karena Course kunci utama entitas adalah CourseID.

Entitas Kursus

Course entity diagram

Buat Models/Course.cs dengan kode berikut:

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; }
    }
}

Properti Enrollments adalah properti navigasi. Entitas Course dapat terkait dengan sejumlah Enrollment entitas.

Atribut DatabaseGenerated ini memungkinkan aplikasi menentukan kunci utama daripada membuat database.

Buat aplikasi. Pengkompilasi menghasilkan beberapa peringatan tentang bagaimana null nilai ditangani. Lihat masalah GitHub ini, Jenis referensi nullable, dan Tutorial: Mengekspresikan niat desain Anda dengan lebih jelas dengan jenis referensi nullable dan non-nullable untuk informasi selengkapnya.

Untuk menghilangkan peringatan dari jenis referensi yang dapat diubah ke null, hapus baris berikut dari ContosoUniversity.csproj file:

<Nullable>enable</Nullable>

Mesin perancah saat ini tidak mendukung jenis referensi nullable, oleh karena itu model yang digunakan dalam perancah juga tidak dapat.

? Hapus anotasi jenis referensi nullable dari public string? RequestId { get; set; } dalam Pages/Error.cshtml.cs sehingga proyek dibangun tanpa peringatan kompilator.

Halaman Siswa Perancah

Di bagian ini, alat perancah ASP.NET Core digunakan untuk menghasilkan:

  • Sebuah EF CoreDbContext kelas. Konteksnya adalah kelas utama yang mengoordinasikan fungsionalitas Kerangka Kerja Entitas untuk model data tertentu. Ini berasal dari Microsoft.EntityFrameworkCore.DbContext kelas .
  • Razor halaman yang menangani operasi Buat, Baca, Perbarui, dan Hapus (CRUD) untuk Student entitas.
  • Buat folder Halaman/Siswa .
  • Di Penjelajah Solusi, klik kanan folder Halaman/Siswa dan pilih Tambahkan>Item Perancah Baru.
  • Dalam dialog Tambahkan Item Perancah Baru:
    • Di tab sebelah kiri, pilih Halaman Umum >Razor terinstal >
    • Pilih Razor Halaman menggunakan Kerangka Kerja Entitas (CRUD)>ADD.
  • Dalam dialog Tambahkan Razor Halaman menggunakan Kerangka Kerja Entitas (CRUD):
    • Di menu drop-down Kelas model, pilih Siswa (ContosoUniversity.Models).
    • Di baris Kelas konteks data, pilih + tanda (plus).
      • Ubah nama konteks data menjadi berakhiran SchoolContext daripada ContosoUniversityContext. Nama konteks yang diperbarui: ContosoUniversity.Data.SchoolContext
      • Pilih Tambahkan untuk menyelesaikan penambahan kelas konteks data.
      • Pilih Tambahkan untuk menyelesaikan dialog Tambahkan Razor Halaman .

Paket berikut diinstal secara otomatis:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Jika langkah sebelumnya gagal, buat proyek dan coba lagi langkah perancah.

Proses perancah:

  • Razor Membuat halaman di folder Halaman/Siswa:
    • Create.cshtml dan Create.cshtml.cs
    • Delete.cshtml dan Delete.cshtml.cs
    • Details.cshtml dan Details.cshtml.cs
    • Edit.cshtml dan Edit.cshtml.cs
    • Index.cshtml dan Index.cshtml.cs
  • Data/SchoolContext.csMembuat .
  • Menambahkan konteks ke injeksi dependensi di Program.cs.
  • Menambahkan database string koneksi ke appsettings.json.

Database string koneksi

Alat perancah menghasilkan string koneksi dalam appsettings.json file.

string koneksi menentukan SQL Server LocalDB:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=SchoolContext-0e9;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

LocalDB adalah versi ringan dari SQL Server Express Database Engine dan ditujukan untuk pengembangan aplikasi, bukan penggunaan produksi. Secara default, LocalDB membuat file .mdf di C:/Users/<user> direktori.

Memperbarui kelas konteks database

Kelas utama yang mengoordinasikan EF Core fungsionalitas untuk model data tertentu adalah kelas konteks database. Konteks berasal dari Microsoft.EntityFrameworkCore.DbContext. Konteks menentukan entitas mana yang disertakan dalam model data. Dalam proyek ini, kelas diberi nama SchoolContext.

Perbarui Data/SchoolContext.cs dengan kode berikut:

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;

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

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

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
    }
}

Kode sebelumnya berubah dari tunggal DbSet<Student> Student ke jamak DbSet<Student> Students. Untuk membuat Razor kode Pages cocok dengan nama baru DBSet , buat perubahan global dari: _context.Student. Untuk: _context.Students.

Ada 8 kejadian.

Karena kumpulan entitas berisi beberapa entitas, banyak pengembang lebih suka DBSet nama properti harus jamak.

Kode yang disorot:

  • DbSet<TEntity> Membuat properti untuk setiap set entitas. Dalam EF Core terminologi:
    • Kumpulan entitas biasanya sesuai dengan tabel database.
    • Entitas sesuai dengan baris dalam tabel.
  • Panggilan OnModelCreating. OnModelCreating:
    • Dipanggil ketika SchoolContext telah diinisialisasi, tetapi sebelum model dikunci dan digunakan untuk menginisialisasi konteks.
    • Diperlukan karena nanti dalam tutorial Student entitas akan memiliki referensi ke entitas lain.

Kami berharap dapat memperbaiki masalah ini dalam rilis mendatang.

Program.cs

ASP.NET Core dibangun dengan injeksi dependensi. Layanan seperti SchoolContext terdaftar dengan injeksi dependensi selama pengaktifan aplikasi. Komponen yang memerlukan layanan ini, seperti Razor Pages, disediakan layanan ini melalui parameter konstruktor. Kode konstruktor yang mendapatkan instans konteks database ditampilkan nanti dalam tutorial.

Alat perancah secara otomatis mendaftarkan kelas konteks dengan kontainer injeksi dependensi.

Garis yang disorot berikut ditambahkan oleh perancah:

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

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

Nama string koneksi diteruskan ke konteks dengan memanggil metode pada DbContextOptions objek. Untuk pengembangan lokal, sistem konfigurasi ASP.NET Core membaca string koneksi dari appsettings.json atau appsettings.Development.json file.

Menambahkan filter pengecualian database

Tambahkan AddDatabaseDeveloperPageExceptionFilter dan UseMigrationsEndPoint seperti yang ditunjukkan dalam kode berikut:

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

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

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
else
{
    app.UseDeveloperExceptionPage();
    app.UseMigrationsEndPoint();
}

Tambahkan paket NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.

Di Konsol Manajer Paket, masukkan yang berikut ini untuk menambahkan paket NuGet:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore

Paket Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet menyediakan middleware inti ASP.NET untuk halaman kesalahan Core Kerangka Kerja Entitas. Middleware ini membantu mendeteksi dan mendiagnosis kesalahan dengan migrasi Entity Framework Core.

AddDatabaseDeveloperPageExceptionFilter menyediakan informasi kesalahan yang bermanfaat di lingkungan pengembangan untuk kesalahan migrasi EF.

Buatlah databasenya

Perbarui Program.cs untuk membuat database jika tidak ada:

using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

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

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
else
{
    app.UseDeveloperExceptionPage();
    app.UseMigrationsEndPoint();
}

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

    var context = services.GetRequiredService<SchoolContext>();
    context.Database.EnsureCreated();
    // DbInitializer.Initialize(context);
}

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

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Metode EnsureCreated ini tidak mengambil tindakan jika database untuk konteks ada. Jika tidak ada database, database dan skema akan dibuat. EnsureCreated mengaktifkan alur kerja berikut untuk menangani perubahan model data:

  • Menghapus database. Setiap data yang ada hilang.
  • Ubah model data. Misalnya, tambahkan EmailAddress bidang.
  • Jalankan aplikasi.
  • EnsureCreated membuat database dengan skema baru.

Alur kerja ini bekerja lebih awal dalam pengembangan ketika skema berkembang dengan cepat, selama data tidak perlu dipertahankan. Situasinya berbeda ketika data yang telah dimasukkan ke dalam database perlu dipertahankan. Ketika demikian, gunakan migrasi.

Kemudian dalam seri tutorial, database dihapus yang dibuat oleh EnsureCreated dan migrasi digunakan. Database yang dibuat oleh EnsureCreated tidak dapat diperbarui dengan menggunakan migrasi.

Menguji aplikasi

  • Jalankan aplikasi.
  • Pilih tautan Siswa lalu Buat Baru.
  • Uji tautan Edit, Detail, dan Hapus.

Seed database

Metode ini EnsureCreated membuat database kosong. Bagian ini menambahkan kode yang mengisi database dengan data pengujian.

Buat Data/DbInitializer.cs dengan kode berikut:

using ContosoUniversity.Models;

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
                new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
            };

            context.Students.AddRange(students);
            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}
            };

            context.Courses.AddRange(courses);
            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},
            };

            context.Enrollments.AddRange(enrollments);
            context.SaveChanges();
        }
    }
}

Kode memeriksa apakah ada siswa dalam database. Jika tidak ada siswa, ia menambahkan data pengujian ke database. Ini membuat data pengujian dalam array daripada List<T> koleksi untuk mengoptimalkan performa.

  • Di Program.cs, hapus // dari DbInitializer.Initialize baris:
using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;

    var context = services.GetRequiredService<SchoolContext>();
    context.Database.EnsureCreated();
    DbInitializer.Initialize(context);
}
  • Hentikan aplikasi jika sedang berjalan, dan jalankan perintah berikut di Package Manager Console (PMC):

    Drop-Database -Confirm
    
    
  • Merespons dengan Y untuk menghapus database.

  • Mulai ulang aplikasi.
  • Pilih halaman Siswa untuk melihat data benih.

Menampilkan database

  • Buka SQL Server Object Explorer (SSOX) dari menu Tampilan di Visual Studio.
  • Di SSOX, pilih (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Nama database dihasilkan dari nama konteks yang disediakan sebelumnya ditambah tanda hubung dan GUID.
  • Perluas simpul Tabel .
  • Klik kanan tabel Siswa dan klik Tampilkan Data untuk melihat kolom yang dibuat dan baris yang disisipkan ke dalam tabel.
  • Klik kanan tabel Siswa dan klik Tampilkan Kode untuk melihat bagaimana model memetakan Student ke Student skema tabel.

Metode EF asinkron di aplikasi web ASP.NET Core

Pemrograman asinkron adalah mode default untuk ASP.NET Core dan EF Core.

Server web memiliki jumlah utas terbatas yang tersedia, dan dalam situasi beban tinggi semua utas yang tersedia mungkin digunakan. Ketika itu terjadi, server tidak dapat memproses permintaan baru sampai utas dikosongkan. Dengan kode sinkron, banyak utas mungkin diikat saat mereka tidak melakukan pekerjaan karena mereka menunggu I/O selesai. Dengan kode asinkron, ketika proses menunggu I/O selesai, utasnya dibebaskan untuk digunakan server untuk memproses permintaan lain. Akibatnya, kode asinkron memungkinkan sumber daya server digunakan lebih efisien, dan server dapat menangani lebih banyak lalu lintas tanpa penundaan.

Kode asinkron memang memperkenalkan sejumlah kecil overhead pada run time. Untuk situasi lalu lintas yang rendah, hit performa dapat diabaikan, sementara untuk situasi lalu lintas yang tinggi, potensi peningkatan performa sangat besar.

Dalam kode berikut, kata kunci asinkron , Task nilai pengembalian, await kata kunci, dan ToListAsync metode membuat kode dijalankan secara asinkron.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Kata async kunci memberi tahu pengkompilasi untuk:
    • Hasilkan panggilan balik untuk bagian isi metode.
    • Buat objek Tugas yang dikembalikan.
  • Task Jenis pengembalian mewakili pekerjaan yang sedang berlangsung.
  • Kata await kunci menyebabkan pengkompilasi membagi metode menjadi dua bagian. Bagian pertama berakhir dengan operasi yang dimulai secara asinkron. Bagian kedua dimasukkan ke dalam metode panggilan balik yang dipanggil ketika operasi selesai.
  • ToListAsync adalah versi asinkron dari ToList metode ekstensi.

Beberapa hal yang perlu diperhatikan saat menulis kode asinkron yang menggunakan EF Core:

  • Hanya pernyataan yang menyebabkan kueri atau perintah dikirim ke database yang dijalankan secara asinkron. Itu termasuk ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync, dan SaveChangesAsync. Ini tidak termasuk pernyataan yang hanya mengubah IQueryable, seperti var students = context.Students.Where(s => s.LastName == "Davolio").
  • Konteks EF Core tidak aman utas: jangan mencoba melakukan beberapa operasi secara paralel.
  • Untuk memanfaatkan manfaat performa kode asinkron, verifikasi bahwa paket pustaka (seperti untuk penomoran halaman) menggunakan asinkron jika mereka memanggil EF Core metode yang mengirim kueri ke database.

Untuk informasi selengkapnya tentang pemrograman asinkron di .NET, lihat Gambaran Umum Asinkron dan Pemrograman asinkron dengan asinkron dan tunggu.

Peringatan

Implementasi asinkron Microsoft.Data.SqlClient memiliki beberapa masalah yang diketahui (#593, #601, dan lainnya). Jika Anda melihat masalah performa yang tidak terduga, coba gunakan eksekusi perintah sinkronisasi, terutama saat berhadapan dengan teks besar atau nilai biner.

Pertimbangan performa

Secara umum, halaman web tidak boleh memuat jumlah baris arbitrer. Kueri harus menggunakan paging atau pendekatan pembatasan. Misalnya, kueri sebelumnya dapat digunakan Take untuk membatasi baris yang dikembalikan:

public async Task OnGetAsync()
{
    Student = await _context.Students.Take(10).ToListAsync();
}

Menghitung tabel besar dalam tampilan dapat mengembalikan respons HTTP 200 yang dibangun sebagian jika pengecualian database terjadi sebagian melalui enumerasi.

Penomoran dibahas nanti dalam tutorial.

Untuk informasi selengkapnya, lihat Pertimbangan performa (EF).

Langkah berikutnya

Gunakan SQLite untuk pengembangan, SQL Server untuk produksi

Ini adalah yang pertama dalam serangkaian tutorial yang menunjukkan cara menggunakan Entity Framework (EF) Core di aplikasi ASP.NET Core Razor Pages . Tutorial ini membangun situs web untuk Universitas Contoso fiktif. Situs ini mencakup fungsionalitas seperti penerimaan siswa, pembuatan kursus, dan penugasan instruktur. Tutorial ini menggunakan pendekatan pertama kode. Untuk informasi tentang mengikuti tutorial ini menggunakan pendekatan pertama database, lihat masalah Github ini.

Unduh atau lihat aplikasi yang telah selesai.Unduh instruksi.

Prasyarat

Mesin database

Instruksi Visual Studio menggunakan SQL Server LocalDB, versi SQL Server Express yang hanya berjalan di Windows.

Pemecahan Masalah

Jika Anda mengalami masalah yang tidak dapat Anda atasi, bandingkan kode Anda dengan proyek yang telah selesai. Cara yang baik untuk mendapatkan bantuan adalah dengan memposting pertanyaan ke StackOverflow.com, menggunakan tag ASP.NET Core atau EF Core tag .

Aplikasi sampel

Aplikasi yang dibangun dalam tutorial ini adalah situs web universitas dasar. Pengguna dapat melihat dan memperbarui informasi siswa, kursus, dan instruktur. Berikut adalah beberapa layar yang dibuat dalam tutorial.

Students Index page

Students Edit page

Gaya UI situs ini didasarkan pada templat proyek bawaan. Fokus tutorial adalah pada cara menggunakan EF Core dengan ASP.NET Core, bukan cara menyesuaikan UI.

Opsional: Buat unduhan sampel

Langkah ini bersifat opsional. Membangun aplikasi yang telah selesai disarankan saat Anda memiliki masalah yang tidak dapat Anda selesaikan. Jika Anda mengalami masalah yang tidak dapat Anda atasi, bandingkan kode Anda dengan proyek yang telah selesai. Unduh instruksi.

Pilih ContosoUniversity.csproj untuk membuka proyek.

  • Bangun proyek.
  • Di Package Manager Console (PMC) jalankan perintah berikut:
Update-Database

Jalankan proyek untuk menyemai database.

Membuat proyek aplikasi web

  1. Mulai Visual Studio dan pilih Buat proyek baru.
  2. Dalam dialog Buat proyek baru, pilih ASP.NET Core Web Application>Next.
  3. Dalam dialog Konfigurasikan proyek baru Anda, masukkan ContosoUniversity untuk Nama proyek. Penting untuk menggunakan nama yang tepat ini termasuk kapitalisasi, sehingga setiap namespace kecocokan saat kode disalin.
  4. Pilih Buat.
  5. Dalam dialog Buat aplikasi web ASP.NET Core baru, pilih:
    1. .NET Core dan ASP.NET Core 5.0 di menu dropdown.
    2. ASP.NET Core Web App.
    3. BuatNew ASP.NET Core Project dialog

Menyiapkan gaya situs

Salin dan tempel kode berikut ke Pages/Shared/_Layout.cshtml dalam file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2021 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>

File tata letak mengatur header situs, footer, dan menu. Kode sebelumnya membuat perubahan berikut:

  • Setiap kemunculan "ContosoUniversity" ke "Contoso University". Ada tiga kejadian.
  • Entri Home menu dan Privacy dihapus.
  • Entri ditambahkan untuk Tentang, Siswa, Kursus, Instruktur, dan Departemen.

Di Pages/Index.cshtml, ganti konten file dengan kode berikut:

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

<div class="row mb-auto">
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 mb-4 ">
                <p class="card-text">
                    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>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column position-static">
                <p class="card-text mb-auto">
                    You can build the application by following the steps in a series of tutorials.
                </p>
                <p>
                    <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column">
                <p class="card-text mb-auto">
                    You can download the completed project from GitHub.
                </p>
                <p>
                    <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
                </p>
            </div>
        </div>
    </div>
</div>

Kode sebelumnya menggantikan teks tentang ASP.NET Core dengan teks tentang aplikasi ini.

Jalankan aplikasi untuk memverifikasi bahwa halaman beranda muncul.

Model data

Bagian berikut membuat model data:

Course-Enrollment-Student data model diagram

Siswa dapat mendaftar di sejumlah kursus, dan kursus dapat memiliki sejumlah siswa yang terdaftar di dalamnya.

Entitas Siswa

Student entity diagram

  • Buat folder Model di folder proyek.

  • Buat Models/Student.cs dengan kode berikut:

    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; }
        }
    }
    

Properti ID menjadi kolom kunci utama tabel database yang sesuai dengan kelas ini. Secara default, EF Core menginterpretasikan properti yang dinamai ID atau classnameID sebagai kunci utama. Jadi nama alternatif yang dikenali secara otomatis untuk Student kunci utama kelas adalah StudentID. Untuk informasi selengkapnya, lihat EF Core - Kunci.

Properti Enrollments adalah properti navigasi. Properti navigasi menyimpan entitas lain yang terkait dengan entitas ini. Dalam hal ini, Enrollments properti Student entitas memegang semua entitas yang terkait dengan Siswa tersebut Enrollment . Misalnya, jika baris Siswa dalam database memiliki dua baris Pendaftaran terkait, properti navigasi berisi dua entitas Pendaftaran tersebut Enrollments .

Dalam database, baris Pendaftaran terkait dengan baris Siswa jika kolomnya StudentID berisi nilai ID siswa. Misalnya, baris Siswa memiliki ID=1. Baris Pendaftaran terkait akan memiliki StudentID = 1. StudentID adalah kunci asing dalam tabel Pendaftaran.

Properti Enrollments didefinisikan sebagai ICollection<Enrollment> karena mungkin ada beberapa entitas Pendaftaran terkait. Jenis koleksi lain dapat digunakan, seperti List<Enrollment> atau HashSet<Enrollment>. Saat ICollection<Enrollment> digunakan, EF Core membuat HashSet<Enrollment> koleksi secara default.

Entitas Pendaftaran

Enrollment entity diagram

Buat Models/Enrollment.cs dengan kode berikut:

using System.ComponentModel.DataAnnotations;

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; }
        [DisplayFormat(NullDisplayText = "No grade")]
        public Grade? Grade { get; set; }

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

Properti EnrollmentID adalah kunci utama; entitas ini menggunakan pola alih-alih ID dengan sendirinyaclassnameID. Untuk model data produksi, banyak pengembang memilih satu pola dan menggunakannya secara konsisten. Tutorial ini menggunakan keduanya hanya untuk menggambarkan bahwa keduanya berfungsi. Menggunakan ID tanpa classname mempermudah penerapan beberapa jenis perubahan model data.

Properti Grade adalah enum. Tanda tanya setelah Grade deklarasi jenis menunjukkan bahwa Grade properti dapat diubah ke null. Nilai null berbeda dari nilai nol—null berarti nilai belum diketahui atau belum ditetapkan.

Properti StudentID adalah kunci asing, dan properti navigasi yang sesuai adalah Student. Entitas Enrollment dikaitkan dengan satu Student entitas, sehingga properti berisi satu Student entitas.

Properti CourseID adalah kunci asing, dan properti navigasi yang sesuai adalah Course. Entitas Enrollment dikaitkan dengan satu Course entitas.

EF Core menafsirkan properti sebagai kunci asing jika bernama <navigation property name><primary key property name>. Misalnya,StudentID adalah kunci asing untuk Student properti navigasi, karena Student kunci utama entitas adalah ID. Properti kunci asing juga dapat diberi nama <primary key property name>. Misalnya, CourseID karena Course kunci utama entitas adalah CourseID.

Entitas Kursus

Course entity diagram

Buat Models/Course.cs dengan kode berikut:

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; }
    }
}

Properti Enrollments adalah properti navigasi. Entitas Course dapat terkait dengan sejumlah Enrollment entitas.

Atribut DatabaseGenerated ini memungkinkan aplikasi menentukan kunci utama daripada membuat database.

Buat proyek untuk memvalidasi bahwa tidak ada kesalahan pengkompilasi.

Halaman Siswa Perancah

Di bagian ini, alat perancah ASP.NET Core digunakan untuk menghasilkan:

  • Sebuah EF CoreDbContext kelas. Konteksnya adalah kelas utama yang mengoordinasikan fungsionalitas Kerangka Kerja Entitas untuk model data tertentu. Ini berasal dari Microsoft.EntityFrameworkCore.DbContext kelas .
  • Razor halaman yang menangani operasi Buat, Baca, Perbarui, dan Hapus (CRUD) untuk Student entitas.
  • Buat folder Halaman/Siswa .
  • Di Penjelajah Solusi, klik kanan folder Halaman/Siswa dan pilih Tambahkan>Item Perancah Baru.
  • Dalam dialog Tambahkan Item Perancah Baru:
    • Di tab sebelah kiri, pilih Halaman Umum >Razor terinstal >
    • Pilih Razor Halaman menggunakan Kerangka Kerja Entitas (CRUD)>ADD.
  • Dalam dialog Tambahkan Razor Halaman menggunakan Kerangka Kerja Entitas (CRUD):
    • Di menu drop-down Kelas model, pilih Siswa (ContosoUniversity.Models).
    • Di baris Kelas konteks data, pilih + tanda (plus).
      • Ubah nama konteks data menjadi berakhiran SchoolContext daripada ContosoUniversityContext. Nama konteks yang diperbarui: ContosoUniversity.Data.SchoolContext
      • Pilih Tambahkan untuk menyelesaikan penambahan kelas konteks data.
      • Pilih Tambahkan untuk menyelesaikan dialog Tambahkan Razor Halaman .

Jika perancah gagal dengan kesalahan 'Install the package Microsoft.VisualStudio.Web.CodeGeneration.Design and try again.', jalankan alat perancah lagi atau lihat masalah GitHub ini.

Paket berikut diinstal secara otomatis:

  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.VisualStudio.Web.CodeGeneration.Design

Jika langkah sebelumnya gagal, buat proyek dan coba lagi langkah perancah.

Proses perancah:

  • Razor Membuat halaman di folder Halaman/Siswa:
    • Create.cshtml dan Create.cshtml.cs
    • Delete.cshtml dan Delete.cshtml.cs
    • Details.cshtml dan Details.cshtml.cs
    • Edit.cshtml dan Edit.cshtml.cs
    • Index.cshtml dan Index.cshtml.cs
  • Data/SchoolContext.csMembuat .
  • Menambahkan konteks ke injeksi dependensi di Startup.cs.
  • Menambahkan database string koneksi ke appsettings.json.

Database string koneksi

Alat perancah menghasilkan string koneksi dalam appsettings.json file.

string koneksi menentukan SQL Server LocalDB:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=CU-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

LocalDB adalah versi ringan dari SQL Server Express Database Engine dan ditujukan untuk pengembangan aplikasi, bukan penggunaan produksi. Secara default, LocalDB membuat file .mdf di C:/Users/<user> direktori.

Memperbarui kelas konteks database

Kelas utama yang mengoordinasikan EF Core fungsionalitas untuk model data tertentu adalah kelas konteks database. Konteks berasal dari Microsoft.EntityFrameworkCore.DbContext. Konteks menentukan entitas mana yang disertakan dalam model data. Dalam proyek ini, kelas diberi nama SchoolContext.

Perbarui Data/SchoolContext.cs dengan kode berikut:

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;

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

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

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
    }
}

Kode sebelumnya berubah dari tunggal DbSet<Student> Student ke jamak DbSet<Student> Students. Untuk membuat Razor kode Pages cocok dengan nama baru DBSet , buat perubahan global dari: _context.Student. Untuk: _context.Students.

Ada 8 kejadian.

Karena kumpulan entitas berisi beberapa entitas, banyak pengembang lebih suka DBSet nama properti harus jamak.

Kode yang disorot:

  • DbSet<TEntity> Membuat properti untuk setiap set entitas. Dalam EF Core terminologi:
    • Kumpulan entitas biasanya sesuai dengan tabel database.
    • Entitas sesuai dengan baris dalam tabel.
  • Panggilan OnModelCreating. OnModelCreating:
    • Dipanggil ketika SchoolContext telah diinisialisasi, tetapi sebelum model dikunci dan digunakan untuk menginisialisasi konteks.
    • Diperlukan karena nanti dalam tutorial Student entitas akan memiliki referensi ke entitas lain.

Bangun proyek untuk memverifikasi tidak ada kesalahan kompilator.

Startup.cs

ASP.NET Core dibangun dengan injeksi dependensi. Layanan seperti SchoolContext terdaftar dengan injeksi dependensi selama pengaktifan aplikasi. Komponen yang memerlukan layanan ini, seperti Razor Pages, disediakan layanan ini melalui parameter konstruktor. Kode konstruktor yang mendapatkan instans konteks database ditampilkan nanti dalam tutorial.

Alat perancah secara otomatis mendaftarkan kelas konteks dengan kontainer injeksi dependensi.

Garis yang disorot berikut ditambahkan oleh perancah:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

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

Nama string koneksi diteruskan ke konteks dengan memanggil metode pada DbContextOptions objek. Untuk pengembangan lokal, sistem konfigurasi ASP.NET Core membaca string koneksi dari appsettings.json file.

Menambahkan filter pengecualian database

Tambahkan AddDatabaseDeveloperPageExceptionFilter dan UseMigrationsEndPoint seperti yang ditunjukkan dalam kode berikut:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

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

    services.AddDatabaseDeveloperPageExceptionFilter();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

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

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Tambahkan paket NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.

Di Konsol Manajer Paket, masukkan yang berikut ini untuk menambahkan paket NuGet:

Install-Package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore

Paket Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore NuGet menyediakan middleware inti ASP.NET untuk halaman kesalahan Core Kerangka Kerja Entitas. Middleware ini membantu mendeteksi dan mendiagnosis kesalahan dengan migrasi Entity Framework Core.

AddDatabaseDeveloperPageExceptionFilter menyediakan informasi kesalahan yang bermanfaat di lingkungan pengembangan untuk kesalahan migrasi EF.

Buatlah databasenya

Perbarui Program.cs untuk membuat database jika tidak ada:

using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

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

            CreateDbIfNotExists(host);

            host.Run();
        }

        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    context.Database.EnsureCreated();
                    // DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

Metode EnsureCreated ini tidak mengambil tindakan jika database untuk konteks ada. Jika tidak ada database, database dan skema akan dibuat. EnsureCreated mengaktifkan alur kerja berikut untuk menangani perubahan model data:

  • Menghapus database. Setiap data yang ada hilang.
  • Ubah model data. Misalnya, tambahkan EmailAddress bidang.
  • Jalankan aplikasi.
  • EnsureCreated membuat database dengan skema baru.

Alur kerja ini bekerja lebih awal dalam pengembangan ketika skema berkembang dengan cepat, selama data tidak perlu dipertahankan. Situasinya berbeda ketika data yang telah dimasukkan ke dalam database perlu dipertahankan. Ketika demikian, gunakan migrasi.

Kemudian dalam seri tutorial, database dihapus yang dibuat oleh EnsureCreated dan migrasi digunakan. Database yang dibuat oleh EnsureCreated tidak dapat diperbarui dengan menggunakan migrasi.

Menguji aplikasi

  • Jalankan aplikasi.
  • Pilih tautan Siswa lalu Buat Baru.
  • Uji tautan Edit, Detail, dan Hapus.

Seed database

Metode ini EnsureCreated membuat database kosong. Bagian ini menambahkan kode yang mengisi database dengan data pengujian.

Buat Data/DbInitializer.cs dengan kode berikut:

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

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
                new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
            };

            context.Students.AddRange(students);
            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}
            };

            context.Courses.AddRange(courses);
            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},
            };

            context.Enrollments.AddRange(enrollments);
            context.SaveChanges();
        }
    }
}

Kode memeriksa apakah ada siswa dalam database. Jika tidak ada siswa, ia menambahkan data pengujian ke database. Ini membuat data pengujian dalam array daripada List<T> koleksi untuk mengoptimalkan performa.

  • Di Program.cs, hapus // dari DbInitializer.Initialize baris:

      context.Database.EnsureCreated();
      DbInitializer.Initialize(context);
    
  • Hentikan aplikasi jika sedang berjalan, dan jalankan perintah berikut di Package Manager Console (PMC):

    Drop-Database -Confirm
    
    
  • Merespons dengan Y untuk menghapus database.

  • Mulai ulang aplikasi.
  • Pilih halaman Siswa untuk melihat data benih.

Menampilkan database

  • Buka SQL Server Object Explorer (SSOX) dari menu Tampilan di Visual Studio.
  • Di SSOX, pilih (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Nama database dihasilkan dari nama konteks yang disediakan sebelumnya ditambah tanda hubung dan GUID.
  • Perluas simpul Tabel .
  • Klik kanan tabel Siswa dan klik Tampilkan Data untuk melihat kolom yang dibuat dan baris yang disisipkan ke dalam tabel.
  • Klik kanan tabel Siswa dan klik Tampilkan Kode untuk melihat bagaimana model memetakan Student ke Student skema tabel.

Kode asinkron

Pemrograman asinkron adalah mode default untuk ASP.NET Core dan EF Core.

Server web memiliki jumlah utas terbatas yang tersedia, dan dalam situasi beban tinggi semua utas yang tersedia mungkin digunakan. Ketika itu terjadi, server tidak dapat memproses permintaan baru sampai utas dikosongkan. Dengan kode sinkron, banyak utas mungkin diikat saat mereka tidak melakukan pekerjaan karena mereka menunggu I/O selesai. Dengan kode asinkron, ketika proses menunggu I/O selesai, utasnya dibebaskan untuk digunakan server untuk memproses permintaan lain. Akibatnya, kode asinkron memungkinkan sumber daya server digunakan lebih efisien, dan server dapat menangani lebih banyak lalu lintas tanpa penundaan.

Kode asinkron memang memperkenalkan sejumlah kecil overhead pada run time. Untuk situasi lalu lintas yang rendah, hit performa dapat diabaikan, sementara untuk situasi lalu lintas yang tinggi, potensi peningkatan performa sangat besar.

Dalam kode berikut, kata kunci asinkron , Task nilai pengembalian, await kata kunci, dan ToListAsync metode membuat kode dijalankan secara asinkron.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Kata async kunci memberi tahu pengkompilasi untuk:
    • Hasilkan panggilan balik untuk bagian isi metode.
    • Buat objek Tugas yang dikembalikan.
  • Task Jenis pengembalian mewakili pekerjaan yang sedang berlangsung.
  • Kata await kunci menyebabkan pengkompilasi membagi metode menjadi dua bagian. Bagian pertama berakhir dengan operasi yang dimulai secara asinkron. Bagian kedua dimasukkan ke dalam metode panggilan balik yang dipanggil ketika operasi selesai.
  • ToListAsync adalah versi asinkron dari ToList metode ekstensi.

Beberapa hal yang perlu diperhatikan saat menulis kode asinkron yang menggunakan EF Core:

  • Hanya pernyataan yang menyebabkan kueri atau perintah dikirim ke database yang dijalankan secara asinkron. Itu termasuk ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync, dan SaveChangesAsync. Ini tidak termasuk pernyataan yang hanya mengubah IQueryable, seperti var students = context.Students.Where(s => s.LastName == "Davolio").
  • Konteks EF Core tidak aman utas: jangan mencoba melakukan beberapa operasi secara paralel.
  • Untuk memanfaatkan manfaat performa kode asinkron, verifikasi bahwa paket pustaka (seperti untuk penomoran halaman) menggunakan asinkron jika mereka memanggil EF Core metode yang mengirim kueri ke database.

Untuk informasi selengkapnya tentang pemrograman asinkron di .NET, lihat Gambaran Umum Asinkron dan Pemrograman asinkron dengan asinkron dan tunggu.

Pertimbangan performa

Secara umum, halaman web tidak boleh memuat jumlah baris arbitrer. Kueri harus menggunakan paging atau pendekatan pembatasan. Misalnya, kueri sebelumnya dapat digunakan Take untuk membatasi baris yang dikembalikan:

public async Task OnGetAsync()
{
    Student = await _context.Students.Take(10).ToListAsync();
}

Menghitung tabel besar dalam tampilan dapat mengembalikan respons HTTP 200 yang dibangun sebagian jika pengecualian database terjadi sebagian melalui enumerasi.

MaxModelBindingCollectionSize default ke 1024. Kumpulan MaxModelBindingCollectionSizekode berikut :

public void ConfigureServices(IServiceCollection services)
{
    var myMaxModelBindingCollectionSize = Convert.ToInt32(
                Configuration["MyMaxModelBindingCollectionSize"] ?? "100");

    services.Configure<MvcOptions>(options =>
           options.MaxModelBindingCollectionSize = myMaxModelBindingCollectionSize);

    services.AddRazorPages();

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

    services.AddDatabaseDeveloperPageExceptionFilter();
}

Lihat Konfigurasi untuk informasi tentang pengaturan konfigurasi seperti MyMaxModelBindingCollectionSize.

Penomoran dibahas nanti dalam tutorial.

Untuk informasi selengkapnya, lihat Pertimbangan performa (EF).

Pengelogan SQL Core Kerangka Kerja Entitas

Konfigurasi pengelogan biasanya disediakan oleh bagian Logging dari file appsettings.{Environment}.json. Untuk mencatat pernyataan SQL, tambahkan "Microsoft.EntityFrameworkCore.Database.Command": "Information" ke appsettings.Development.json file:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDB-2;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
     ,"Microsoft.EntityFrameworkCore.Database.Command": "Information"
    }
  },
  "AllowedHosts": "*"
}

Dengan ON sebelumnya JS, pernyataan SQL ditampilkan pada baris perintah dan di jendela output Visual Studio.

Untuk informasi selengkapnya, lihat Pengelogan di .NET Core dan ASP.NET Core dan masalah GitHub ini.

Langkah berikutnya

Gunakan SQLite untuk pengembangan, SQL Server untuk produksi

Ini adalah yang pertama dalam serangkaian tutorial yang menunjukkan cara menggunakan Entity Framework (EF) Core di aplikasi ASP.NET Core Razor Pages . Tutorial ini membangun situs web untuk Universitas Contoso fiktif. Situs ini mencakup fungsionalitas seperti penerimaan siswa, pembuatan kursus, dan penugasan instruktur. Tutorial ini menggunakan pendekatan pertama kode. Untuk informasi tentang mengikuti tutorial ini menggunakan pendekatan pertama database, lihat masalah Github ini.

Unduh atau lihat aplikasi yang telah selesai.Unduh instruksi.

Prasyarat

Mesin database

Instruksi Visual Studio menggunakan SQL Server LocalDB, versi SQL Server Express yang hanya berjalan di Windows.

Instruksi Visual Studio Code menggunakan SQLite, mesin database lintas platform.

Jika Anda memilih untuk menggunakan SQLite, unduh dan instal alat pihak ketiga untuk mengelola dan melihat database SQLite, seperti Browser DB untuk SQLite.

Pemecahan Masalah

Jika Anda mengalami masalah yang tidak dapat Anda atasi, bandingkan kode Anda dengan proyek yang telah selesai. Cara yang baik untuk mendapatkan bantuan adalah dengan memposting pertanyaan ke StackOverflow.com, menggunakan tag ASP.NET Core atau EF Core tag .

Aplikasi sampel

Aplikasi yang dibangun dalam tutorial ini adalah situs web universitas dasar. Pengguna dapat melihat dan memperbarui informasi siswa, kursus, dan instruktur. Berikut adalah beberapa layar yang dibuat dalam tutorial.

Students Index page

Students Edit page

Gaya UI situs ini didasarkan pada templat proyek bawaan. Fokus tutorial adalah pada cara menggunakan EF Core, bukan cara menyesuaikan UI.

Ikuti tautan di bagian atas halaman untuk mendapatkan kode sumber untuk proyek yang telah selesai. Folder cu30 memiliki kode untuk tutorial versi ASP.NET Core 3.0. File yang mencerminkan status kode untuk tutorial 1-7 dapat ditemukan di folder cu30snapshots .

Untuk menjalankan aplikasi setelah mengunduh proyek yang telah selesai:

  • Bangun proyek.

  • Di Package Manager Console (PMC) jalankan perintah berikut:

    Update-Database
    
  • Jalankan proyek untuk menyemai database.

Membuat proyek aplikasi web

  • Dari menu File Visual Studio, pilih Proyek Baru>.
  • Pilih ASP.NET Core Web Application.
  • Beri nama proyek ContosoUniversity. Penting untuk menggunakan nama yang tepat ini termasuk kapitalisasi, sehingga namespace cocok saat kode disalin dan ditempelkan.
  • Pilih .NET Core dan ASP.NET Core 3.0 di menu dropdown, lalu pilih Aplikasi Web.

Menyiapkan gaya situs

Siapkan header situs, footer, dan menu dengan memperbarui Pages/Shared/_Layout.cshtml:

  • Ubah setiap kemunculan "ContosoUniversity" menjadi "Contoso University". Ada tiga kejadian.

  • Home Hapus entri menu dan Privacy , dan tambahkan entri untuk Tentang, Siswa, Kursus, Instruktur, dan Departemen.

Perubahan disorot.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - Contoso University</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">Contoso University</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/About">About</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Students/Index">Students</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Courses/Index">Courses</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Instructors/Index">Instructors</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Departments/Index">Departments</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2019 - Contoso University - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/jquery/dist/jquery.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>

    @RenderSection("Scripts", required: false)
</body>
</html>

Di Pages/Index.cshtml, ganti konten file dengan kode berikut untuk mengganti teks tentang ASP.NET Core dengan teks tentang aplikasi ini:

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

<div class="row mb-auto">
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 mb-4 ">
                <p class="card-text">
                    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>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column position-static">
                <p class="card-text mb-auto">
                    You can build the application by following the steps in a series of tutorials.
                </p>
                <p>
                    <a href="https://docs.microsoft.com/aspnet/core/data/ef-rp/intro" class="stretched-link">See the tutorial</a>
                </p>
            </div>
        </div>
    </div>
    <div class="col-md-4">
        <div class="row no-gutters border mb-4">
            <div class="col p-4 d-flex flex-column">
                <p class="card-text mb-auto">
                    You can download the completed project from GitHub.
                </p>
                <p>
                    <a href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-rp/intro/samples" class="stretched-link">See project source code</a>
                </p>
            </div>
        </div>
    </div>
</div>

Jalankan aplikasi untuk memverifikasi bahwa halaman beranda muncul.

Model data

Bagian berikut membuat model data:

Course-Enrollment-Student data model diagram

Siswa dapat mendaftar di sejumlah kursus, dan kursus dapat memiliki sejumlah siswa yang terdaftar di dalamnya.

Entitas Siswa

Student entity diagram

  • Buat folder Model di folder proyek.

  • Buat Models/Student.cs dengan kode berikut:

    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; }
        }
    }
    

Properti ID menjadi kolom kunci utama tabel database yang sesuai dengan kelas ini. Secara default, EF Core menginterpretasikan properti yang dinamai ID atau classnameID sebagai kunci utama. Jadi nama alternatif yang dikenali secara otomatis untuk Student kunci utama kelas adalah StudentID. Untuk informasi selengkapnya, lihat EF Core - Kunci.

Properti Enrollments adalah properti navigasi. Properti navigasi menyimpan entitas lain yang terkait dengan entitas ini. Dalam hal ini, Enrollments properti Student entitas memegang semua entitas yang terkait dengan Siswa tersebut Enrollment . Misalnya, jika baris Siswa dalam database memiliki dua baris Pendaftaran terkait, properti navigasi berisi dua entitas Pendaftaran tersebut Enrollments .

Dalam database, baris Pendaftaran terkait dengan baris Siswa jika kolom StudentID-nya berisi nilai ID siswa. Misalnya, baris Siswa memiliki ID=1. Baris Pendaftaran terkait akan memiliki StudentID = 1. StudentID adalah kunci asing dalam tabel Pendaftaran.

Properti Enrollments didefinisikan sebagai ICollection<Enrollment> karena mungkin ada beberapa entitas Pendaftaran terkait. Anda dapat menggunakan jenis koleksi lain, seperti List<Enrollment> atau HashSet<Enrollment>. Saat ICollection<Enrollment> digunakan, EF Core membuat HashSet<Enrollment> koleksi secara default.

Entitas Pendaftaran

Enrollment entity diagram

Buat Models/Enrollment.cs dengan kode berikut:

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; }
    }
}

Properti EnrollmentID adalah kunci utama; entitas ini menggunakan pola alih-alih ID dengan sendirinyaclassnameID. Untuk model data produksi, pilih satu pola dan gunakan secara konsisten. Tutorial ini menggunakan keduanya hanya untuk menggambarkan bahwa keduanya berfungsi. Menggunakan ID tanpa classname mempermudah penerapan beberapa jenis perubahan model data.

Properti Grade adalah enum. Tanda tanya setelah Grade deklarasi jenis menunjukkan bahwa Grade properti dapat diubah ke null. Nilai null berbeda dari nilai nol—null berarti nilai belum diketahui atau belum ditetapkan.

Properti StudentID adalah kunci asing, dan properti navigasi yang sesuai adalah Student. Entitas Enrollment dikaitkan dengan satu Student entitas, sehingga properti berisi satu Student entitas.

Properti CourseID adalah kunci asing, dan properti navigasi yang sesuai adalah Course. Entitas Enrollment dikaitkan dengan satu Course entitas.

EF Core menafsirkan properti sebagai kunci asing jika bernama <navigation property name><primary key property name>. Misalnya,StudentID adalah kunci asing untuk Student properti navigasi, karena Student kunci utama entitas adalah ID. Properti kunci asing juga dapat diberi nama <primary key property name>. Misalnya, CourseID karena Course kunci utama entitas adalah CourseID.

Entitas Kursus

Course entity diagram

Buat Models/Course.cs dengan kode berikut:

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; }
    }
}

Properti Enrollments adalah properti navigasi. Entitas Course dapat terkait dengan sejumlah Enrollment entitas.

Atribut DatabaseGenerated ini memungkinkan aplikasi menentukan kunci utama daripada membuat database.

Buat proyek untuk memvalidasi bahwa tidak ada kesalahan pengkompilasi.

Halaman Siswa Perancah

Di bagian ini, Anda menggunakan alat perancah ASP.NET Core untuk menghasilkan:

  • Kelas EF Corekonteks . Konteksnya adalah kelas utama yang mengoordinasikan fungsionalitas Kerangka Kerja Entitas untuk model data tertentu. Ini berasal dari Microsoft.EntityFrameworkCore.DbContext kelas .
  • Razor halaman yang menangani operasi Buat, Baca, Perbarui, dan Hapus (CRUD) untuk Student entitas.
  • Buat folder Siswa di folder Halaman .
  • Di Penjelajah Solusi, klik kanan folder Halaman/Siswa dan pilih Tambahkan>Item Perancah Baru.
  • Dalam dialog Tambahkan Perancah, pilih Razor Halaman menggunakan Kerangka Kerja Entitas (CRUD)>ADD.
  • Dalam dialog Tambahkan Razor Halaman menggunakan Kerangka Kerja Entitas (CRUD):
    • Di menu drop-down Kelas model, pilih Siswa (ContosoUniversity.Models).
    • Di baris Kelas konteks data, pilih + tanda (plus).
    • Ubah nama konteks data dari ContosoUniversity.Models.ContosoUniversityContext menjadi ContosoUniversity.Data.SchoolContext.
    • Pilih Tambahkan.

Paket berikut diinstal secara otomatis:

  • Microsoft.VisualStudio.Web.CodeGeneration.Design
  • Microsoft.EntityFrameworkCore.SqlServer
  • Microsoft.Extensions.Logging.Debug
  • Microsoft.EntityFrameworkCore.Tools

Jika Anda memiliki masalah dengan langkah sebelumnya, buat proyek dan coba lagi langkah perancah.

Proses perancah:

  • Razor Membuat halaman di folder Halaman/Siswa:
    • Create.cshtml dan Create.cshtml.cs
    • Delete.cshtml dan Delete.cshtml.cs
    • Details.cshtml dan Details.cshtml.cs
    • Edit.cshtml dan Edit.cshtml.cs
    • Index.cshtml dan Index.cshtml.cs
  • Data/SchoolContext.csMembuat .
  • Menambahkan konteks ke injeksi dependensi di Startup.cs.
  • Menambahkan database string koneksi ke appsettings.json.

Database string koneksi

File appsettings.json menentukan string koneksi SQL Server LocalDB.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "SchoolContext": "Server=(localdb)\\mssqllocaldb;Database=SchoolContext6;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

LocalDB adalah versi ringan dari SQL Server Express Database Engine dan ditujukan untuk pengembangan aplikasi, bukan penggunaan produksi. Secara default, LocalDB membuat file .mdf di C:/Users/<user> direktori.

Memperbarui kelas konteks database

Kelas utama yang mengoordinasikan EF Core fungsionalitas untuk model data tertentu adalah kelas konteks database. Konteks berasal dari Microsoft.EntityFrameworkCore.DbContext. Konteks menentukan entitas mana yang disertakan dalam model data. Dalam proyek ini, kelas diberi nama SchoolContext.

Perbarui Data/SchoolContext.cs dengan kode berikut:

using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Models;

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

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

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
        }
    }
}

Kode yang disorot DbSet<TEntity> membuat properti untuk setiap set entitas. Dalam EF Core terminologi:

  • Kumpulan entitas biasanya sesuai dengan tabel database.
  • Entitas sesuai dengan baris dalam tabel.

Karena kumpulan entitas berisi beberapa entitas, properti DBSet harus berupa nama jamak. Karena alat perancah membuatStudent DBSet, langkah ini mengubahnya menjadi jamak Students.

Untuk membuat Razor kode Pages cocok dengan nama DBSet baru, buat perubahan global di seluruh proyek menjadi _context.Student_context.Students. Ada 8 kejadian.

Bangun proyek untuk memverifikasi tidak ada kesalahan kompilator.

Startup.cs

ASP.NET Core dibangun dengan injeksi dependensi. Layanan (seperti EF Core konteks database) terdaftar dengan injeksi dependensi selama startup aplikasi. Komponen yang memerlukan layanan ini (seperti Razor Pages) disediakan layanan ini melalui parameter konstruktor. Kode konstruktor yang mendapatkan instans konteks database ditampilkan nanti dalam tutorial.

Alat perancah secara otomatis mendaftarkan kelas konteks dengan kontainer injeksi dependensi.

  • Dalam ConfigureServices, garis yang disorot ditambahkan oleh perancah:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    
        services.AddDbContext<SchoolContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("SchoolContext")));
    }
    

Nama string koneksi diteruskan ke konteks dengan memanggil metode pada DbContextOptions objek. Untuk pengembangan lokal, sistem konfigurasi ASP.NET Core membaca string koneksi dari appsettings.json file.

Buatlah databasenya

Perbarui Program.cs untuk membuat database jika tidak ada:

using ContosoUniversity.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;

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

            CreateDbIfNotExists(host);

            host.Run();
        }

        private static void CreateDbIfNotExists(IHost host)
        {
            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;
                try
                {
                    var context = services.GetRequiredService<SchoolContext>();
                    context.Database.EnsureCreated();
                    // DbInitializer.Initialize(context);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred creating the DB.");
                }
            }
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

Metode EnsureCreated ini tidak mengambil tindakan jika database untuk konteks ada. Jika tidak ada database, database dan skema akan dibuat. EnsureCreated mengaktifkan alur kerja berikut untuk menangani perubahan model data:

  • Menghapus database. Setiap data yang ada hilang.
  • Ubah model data. Misalnya, tambahkan EmailAddress bidang.
  • Jalankan aplikasi.
  • EnsureCreated membuat database dengan skema baru.

Alur kerja ini bekerja dengan baik di awal pengembangan ketika skema berkembang dengan cepat, selama Anda tidak perlu mempertahankan data. Situasinya berbeda ketika data yang telah dimasukkan ke dalam database perlu dipertahankan. Ketika demikian, gunakan migrasi.

Kemudian dalam seri tutorial, Anda menghapus database yang dibuat oleh EnsureCreated dan menggunakan migrasi sebagai gantinya. Database yang dibuat oleh EnsureCreated tidak dapat diperbarui dengan menggunakan migrasi.

Menguji aplikasi

  • Jalankan aplikasi.
  • Pilih tautan Siswa lalu Buat Baru.
  • Uji tautan Edit, Detail, dan Hapus.

Seed database

Metode ini EnsureCreated membuat database kosong. Bagian ini menambahkan kode yang mengisi database dengan data pengujian.

Buat Data/DbInitializer.cs dengan kode berikut:

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

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

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

            var students = new Student[]
            {
                new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2019-09-01")},
                new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2017-09-01")},
                new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2016-09-01")},
                new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2018-09-01")},
                new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2019-09-01")}
            };

            context.Students.AddRange(students);
            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}
            };

            context.Courses.AddRange(courses);
            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},
            };

            context.Enrollments.AddRange(enrollments);
            context.SaveChanges();
        }
    }
}

Kode memeriksa apakah ada siswa dalam database. Jika tidak ada siswa, ia menambahkan data pengujian ke database. Ini membuat data pengujian dalam array daripada List<T> koleksi untuk mengoptimalkan performa.

  • Di Program.cs, ganti EnsureCreated panggilan dengan DbInitializer.Initialize panggilan:

    // context.Database.EnsureCreated();
    DbInitializer.Initialize(context);
    

Hentikan aplikasi jika sedang berjalan, dan jalankan perintah berikut di Package Manager Console (PMC):

Drop-Database
  • Mulai ulang aplikasi.

  • Pilih halaman Siswa untuk melihat data benih.

Menampilkan database

  • Buka SQL Server Object Explorer (SSOX) dari menu Tampilan di Visual Studio.
  • Di SSOX, pilih (localdb)\MSSQLLocalDB > Databases > SchoolContext-{GUID}. Nama database dihasilkan dari nama konteks yang Anda berikan sebelumnya ditambah tanda hubung dan GUID.
  • Perluas simpul Tabel .
  • Klik kanan tabel Siswa dan klik Tampilkan Data untuk melihat kolom yang dibuat dan baris yang disisipkan ke dalam tabel.
  • Klik kanan tabel Siswa dan klik Tampilkan Kode untuk melihat bagaimana model memetakan Student ke Student skema tabel.

Kode asinkron

Pemrograman asinkron adalah mode default untuk ASP.NET Core dan EF Core.

Server web memiliki jumlah utas terbatas yang tersedia, dan dalam situasi beban tinggi semua utas yang tersedia mungkin digunakan. Ketika itu terjadi, server tidak dapat memproses permintaan baru sampai utas dikosongkan. Dengan kode sinkron, banyak utas mungkin diikat sementara mereka tidak benar-benar melakukan pekerjaan apa pun karena mereka menunggu I/O selesai. Dengan kode asinkron, ketika proses menunggu I/O selesai, utasnya dibebaskan untuk digunakan server untuk memproses permintaan lain. Akibatnya, kode asinkron memungkinkan sumber daya server digunakan lebih efisien, dan server dapat menangani lebih banyak lalu lintas tanpa penundaan.

Kode asinkron memang memperkenalkan sejumlah kecil overhead pada run time. Untuk situasi lalu lintas yang rendah, hit performa dapat diabaikan, sementara untuk situasi lalu lintas yang tinggi, potensi peningkatan performa sangat besar.

Dalam kode berikut, kata kunci asinkron , Task<T> nilai pengembalian, await kata kunci, dan ToListAsync metode membuat kode dijalankan secara asinkron.

public async Task OnGetAsync()
{
    Students = await _context.Students.ToListAsync();
}
  • Kata async kunci memberi tahu pengkompilasi untuk:
    • Hasilkan panggilan balik untuk bagian isi metode.
    • Buat objek Tugas yang dikembalikan.
  • Task<T> Jenis pengembalian mewakili pekerjaan yang sedang berlangsung.
  • Kata await kunci menyebabkan pengkompilasi membagi metode menjadi dua bagian. Bagian pertama berakhir dengan operasi yang dimulai secara asinkron. Bagian kedua dimasukkan ke dalam metode panggilan balik yang dipanggil ketika operasi selesai.
  • ToListAsync adalah versi asinkron dari ToList metode ekstensi.

Beberapa hal yang perlu diperhatikan saat menulis kode asinkron yang menggunakan EF Core:

  • Hanya pernyataan yang menyebabkan kueri atau perintah dikirim ke database yang dijalankan secara asinkron. Itu termasuk ToListAsync, SingleOrDefaultAsync, FirstOrDefaultAsync, dan SaveChangesAsync. Ini tidak termasuk pernyataan yang hanya mengubah IQueryable, seperti var students = context.Students.Where(s => s.LastName == "Davolio").
  • Konteks EF Core tidak aman utas: jangan mencoba melakukan beberapa operasi secara paralel.
  • Untuk memanfaatkan manfaat performa kode asinkron, verifikasi bahwa paket pustaka (seperti untuk penomoran halaman) menggunakan asinkron jika mereka memanggil EF Core metode yang mengirim kueri ke database.

Untuk informasi selengkapnya tentang pemrograman asinkron di .NET, lihat Gambaran Umum Asinkron dan Pemrograman asinkron dengan asinkron dan tunggu.

Langkah berikutnya