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

Note

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 10 dari artikel ini.

Warning

Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 10 dari artikel ini.

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 code-first. Untuk informasi tentang mengikuti tutorial ini menggunakan pendekatan database pertama, lihat topik Github ini.

Unduh atau lihat aplikasi yang telah selesai.Unduh instruksi.

Prerequisites

Mesin database

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

Troubleshooting

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.

Halaman Indeks Siswa

Halaman Edit untuk Siswa

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.

    Membuat proyek baru dari jendela mulai

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

    Membuat 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.

    Informasi tambahan

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:

  • Ubah setiap kemunculan "ContosoUniversity" menjadi "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:

Kursus- diagram model dataEnrollment-Student

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

Entitas Siswa

Diagram entitas siswa

  • 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 berisi entitas lain yang terkait dengan entitas ini. Dalam hal ini, properti Enrollments dari entitas Student menyimpan semua entitas Enrollment yang terkait dengan Student tersebut. 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. Misalkan, baris Student 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 secara bawaan membuat koleksi HashSet<Enrollment>.

Entitas Pendaftaran

Diagram entitas pendaftaran

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 classnameID alih-alih ID dengan sendirinya. 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 atribut dapat bernilai null. Nilai null berbeda dengan nilai nol—null berarti nilai tersebut 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

Diagram entitas mata kuliah

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 primer alih-alih membiarkan database membuatnya.

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

Untuk menghilangkan peringatan dari tipe referensi nullable, hapus baris berikut dari file ContosoUniversity.csproj:

<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 tipe referensi nullable dari public string? RequestId { get; set; } pada Pages/Error.cshtml.cs agar proyek dapat dibangun tanpa peringatan kompilator.

Halaman Panduan Siswa

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 >> terinstal Razor
    • 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 penyanggaan:

  • 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
  • Membuat Data/SchoolContext.cs.
  • Menambahkan konteks pada injeksi dependensi di Program.cs.
  • Menambahkan string koneksi database 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.

Perbarui 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 kode Razor Pages sesuai dengan DBSet nama baru, lakukan perubahan global dari: _context.Student. hingga: _context.Students.

Ada 8 kejadian.

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

Kode yang disorot:

  • Membuat sebuah DbSet<TEntity> properti untuk setiap kumpulan entitas. Dalam terminologi EF Core:
    • Kumpulan entitas biasanya sesuai dengan tabel database.
    • Entitas sesuai dengan baris dalam tabel.
  • Panggilan OnModelCreating. OnModelCreating:
    • Dipanggil ketika SchoolContext telah diinisialisasi tetapi sebelum model diamankan 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 didaftarkan melalui injeksi dependensi saat aplikasi dimulai. 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.

Tambahkan filter pengecualian basis data

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 NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore menyediakan middleware ASP.NET Core untuk halaman kesalahan Entity Framework Core. 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 basis data belum ada, sistem akan membuat basis data dan skemanya. EnsureCreated mengaktifkan alur kerja berikut untuk menangani perubahan model data:

  • Menghapus database. Setiap data yang ada hilang.
  • Ubah model data. Misalnya, tambahkan kolom EmailAddress.
  • 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. Jika demikian, gunakan migrasi.

Nanti dalam seri tutorial, basis data yang dibuat oleh EnsureCreated akan dihapus dan migrasi akan 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.

Isi basis data awal

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 bentuk array, bukan dalam koleksi List<T>, untuk mengoptimalkan kinerja.

  • 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 awal.

Lihat 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 menimbulkan sejumlah kecil beban tambahan saat runtime. Untuk kondisi trafik rendah, penurunan kinerjanya dapat diabaikan, sedangkan untuk kondisi trafik tinggi, potensi peningkatan kinerjanya signifikan.

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();
}
  • async keyword memberi tahu kompilator untuk:
    • Buat callback untuk bagian-bagian dalam isi metode.
    • Buat objek Tugas yang dikembalikan.
  • Task Tipe pengembalian merepresentasikan operasi 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 untuk thread: jangan mencoba menjalankan 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.

Warning

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.

Paginasi akan dibahas nanti dalam tutorial ini.

Untuk informasi selengkapnya, lihat Pertimbangan performa (EF).

Langkah selanjutnya

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 code-first. Untuk informasi tentang mengikuti tutorial ini menggunakan pendekatan database pertama, lihat topik Github ini.

Unduh atau lihat aplikasi yang telah selesai.Unduh instruksi.

Prerequisites

Mesin database

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

Troubleshooting

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.

Halaman Indeks Siswa

Halaman Edit untuk Siswa

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 persis ini, termasuk penggunaan huruf besar/kecil, agar setiap namespace cocok 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. BuatDialog Proyek Inti ASP.NET Baru

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:

  • Ubah setiap kemunculan "ContosoUniversity" menjadi "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:

Kursus- diagram model dataEnrollment-Student

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

Entitas Siswa

Diagram entitas siswa

  • 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 berisi entitas lain yang terkait dengan entitas ini. Dalam hal ini, properti Enrollments dari entitas Student menyimpan semua entitas Enrollment yang terkait dengan Student tersebut. 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. Misalkan, baris Student 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 secara bawaan membuat koleksi HashSet<Enrollment>.

Entitas Pendaftaran

Diagram entitas pendaftaran

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 classnameID alih-alih ID dengan sendirinya. 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 atribut dapat bernilai null. Nilai null berbeda dengan nilai nol—null berarti nilai tersebut 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

Diagram entitas mata kuliah

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 primer alih-alih membiarkan database membuatnya.

Buat proyek untuk memvalidasi bahwa tidak ada kesalahan pengkompilasi.

Halaman Panduan Siswa

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 >> terinstal Razor
    • 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 penyanggaan:

  • 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
  • Membuat Data/SchoolContext.cs.
  • Menambahkan konteks pada injeksi dependensi di Startup.cs.
  • Menambahkan string koneksi database 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.

Perbarui 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 kode Razor Pages sesuai dengan DBSet nama baru, lakukan perubahan global dari: _context.Student. hingga: _context.Students.

Ada 8 kejadian.

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

Kode yang disorot:

  • Membuat sebuah DbSet<TEntity> properti untuk setiap kumpulan entitas. Dalam terminologi EF Core:
    • Kumpulan entitas biasanya sesuai dengan tabel database.
    • Entitas sesuai dengan baris dalam tabel.
  • Panggilan OnModelCreating. OnModelCreating:
    • Dipanggil ketika SchoolContext telah diinisialisasi tetapi sebelum model diamankan 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 didaftarkan melalui injeksi dependensi saat aplikasi dimulai. 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.

Tambahkan filter pengecualian basis data

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 NuGet Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore menyediakan middleware ASP.NET Core untuk halaman kesalahan Entity Framework Core. 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 basis data belum ada, sistem akan membuat basis data dan skemanya. EnsureCreated mengaktifkan alur kerja berikut untuk menangani perubahan model data:

  • Menghapus database. Setiap data yang ada hilang.
  • Ubah model data. Misalnya, tambahkan kolom EmailAddress.
  • 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. Jika demikian, gunakan migrasi.

Nanti dalam seri tutorial, basis data yang dibuat oleh EnsureCreated akan dihapus dan migrasi akan 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.

Isi basis data awal

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 bentuk array, bukan dalam koleksi List<T>, untuk mengoptimalkan kinerja.

  • 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 awal.

Lihat 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 menimbulkan sejumlah kecil beban tambahan saat runtime. Untuk kondisi trafik rendah, penurunan kinerjanya dapat diabaikan, sedangkan untuk kondisi trafik tinggi, potensi peningkatan kinerjanya signifikan.

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();
}
  • async keyword memberi tahu kompilator untuk:
    • Buat callback untuk bagian-bagian dalam isi metode.
    • Buat objek Tugas yang dikembalikan.
  • Task Tipe pengembalian merepresentasikan operasi 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 untuk thread: jangan mencoba menjalankan 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 secara default bernilai 1024. Kode berikut menetapkan MaxModelBindingCollectionSize:

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.

Paginasi akan dibahas nanti dalam tutorial ini.

Untuk informasi selengkapnya, lihat Pertimbangan performa (EF).

Pencatatan Log SQL pada Entity Framework Core

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 JSON sebelumnya, pernyataan SQL ditampilkan pada baris perintah dan di jendela output Visual Studio.

Untuk informasi selengkapnya, lihat sumber daya berikut ini:

Langkah selanjutnya

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 code-first. Untuk informasi tentang mengikuti tutorial ini menggunakan pendekatan database pertama, lihat topik Github ini.

Unduh atau lihat aplikasi yang telah selesai.Unduh instruksi.

Prerequisites

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.

Troubleshooting

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.

Halaman Indeks Siswa

Halaman Edit untuk Siswa

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, pilihProyek>.
  • 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 tersebut 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:

Kursus- diagram model dataEnrollment-Student

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

Entitas Siswa

Diagram entitas siswa

  • 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 berisi entitas lain yang terkait dengan entitas ini. Dalam hal ini, properti Enrollments dari entitas Student menyimpan semua entitas Enrollment yang terkait dengan Student tersebut. 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. Misalkan, baris Student 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 secara bawaan membuat koleksi HashSet<Enrollment>.

Entitas Pendaftaran

Diagram entitas pendaftaran

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 classnameID alih-alih ID dengan sendirinya. 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 atribut dapat bernilai null. Nilai null berbeda dengan nilai nol—null berarti nilai tersebut 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

Diagram entitas mata kuliah

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 primer alih-alih membiarkan database membuatnya.

Buat proyek untuk memvalidasi bahwa tidak ada kesalahan pengkompilasi.

Halaman Panduan Siswa

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 penyanggaan:

  • 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
  • Membuat Data/SchoolContext.cs.
  • Menambahkan konteks pada injeksi dependensi di Startup.cs.
  • Menambahkan string koneksi database 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.

Perbarui 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 membuat properti DbSet<TEntity> untuk setiap set entitas. Dalam terminologi EF Core:

  • 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 scaffolding membuat sebuahStudent DBSet, langkah ini mengubahnya ke bentuk jamak Students.

Agar kode Razor Pages sesuai dengan nama DBSet yang baru, lakukan penggantian global di seluruh proyek dari _context.Student menjadi _context.Students. Ada 8 kejadian.

Bangun proyek untuk memverifikasi tidak ada kesalahan kompilator.

Startup.cs

ASP.NET Core dibangun dengan injeksi dependensi. Layanan (seperti konteks database EF Core) didaftarkan melalui injeksi dependensi saat aplikasi dimulai. 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 basis data belum ada, sistem akan membuat basis data dan skemanya. EnsureCreated mengaktifkan alur kerja berikut untuk menangani perubahan model data:

  • Menghapus database. Setiap data yang ada hilang.
  • Ubah model data. Misalnya, tambahkan kolom EmailAddress.
  • 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. Jika 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.

Isi basis data awal

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 bentuk array, bukan dalam koleksi List<T>, untuk mengoptimalkan kinerja.

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

    // 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 awal.

Lihat 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 menimbulkan sejumlah kecil beban tambahan saat runtime. Untuk kondisi trafik rendah, penurunan kinerjanya dapat diabaikan, sedangkan untuk kondisi trafik tinggi, potensi peningkatan kinerjanya signifikan.

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();
}
  • async keyword memberi tahu kompilator untuk:
    • Buat callback untuk bagian-bagian dalam isi metode.
    • Buat objek Tugas yang dikembalikan.
  • Task<T> Tipe pengembalian merepresentasikan operasi 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 untuk thread: jangan mencoba menjalankan 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 selanjutnya