using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
public class SchoolContext : DbContext
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
上述程式碼會為每個實體集建立 DbSet
屬性。 以 EF 用語來說:
實體集通常會對應到資料庫資料表。
實體會對應至資料表中的資料列。
即便省略 DbSet<Enrollment>
及 DbSet<Course>
陳述式,其結果也會相同。 EF 會隱含地包含那些項目,因為:
Student
實體會參考 Enrollment
實體。
Enrollment
實體會參考 Course
實體。
資料庫建立時,EF 會建立和 DbSet
屬性名稱相同的資料表。 集合的屬性名稱通常是複數。 例如,Students
而非 Student
。 針對是否要複數化資料表名稱,開發人員並沒有共識。 在此系列教學課程中,預設行為將由 DbContext
中指定的單數資料表名稱覆寫。 若要完成這項操作,請在最後一個 DbSet 屬性後方新增下列醒目提示程式碼。
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
public class SchoolContext : DbContext
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
註冊 SchoolContext
ASP.NET Core 包含了相依性插入。 服務 (例如 EF 資料庫內容) 會在應用程式啟動期間使用相依性插入來註冊。 接著便會透過建構函式參數,針對需要這些服務的元件 (例如 MVC 控制器) 來提供服務。 本教學課程稍後會展示取得內容執行個體的控制器建構函式。
若要將 SchoolContext
註冊為服務,請開啟 Startup.cs
,並將醒目標示的程式碼新增至 ConfigureServices
方法。
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ContosoUniversity
public class Startup
public Startup(IConfiguration configuration)
Configuration = configuration;
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllersWithViews();
連接字串的名稱,會透過呼叫 DbContextOptionsBuilder
物件上的方法來傳遞至內容。 作為本機開發之用,ASP.NET Core 設定系統會從 appsettings.json
檔案讀取連接字串。
請開啟 appsettings.json
檔案並新增連接字串,如下列標記所示:
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
"AllowedHosts": "*"
新增資料庫例外狀況篩選條件
將 AddDatabaseDeveloperPageExceptionFilter 新增至 ConfigureServices
,如下列程式碼所示:
public void ConfigureServices(IServiceCollection services)
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddControllersWithViews();
AddDatabaseDeveloperPageExceptionFilter
會在開發環境中提供有用的錯誤資訊。
SQL Server Express LocalDB (本地資料庫)
連接字串會指定 SQL Server LocalDB。 LocalDB 是輕量版的 SQL Server Express Database Engine,旨在用於應用程序開發,而不是生產用途。 LocalDB 會依需求啟動,並以使用者模式執行,因此沒有複雜的組態。 LocalDB 預設會在 目錄中建立 C:/Users/<user>
資料庫檔案。
使用測試資料將 DB 初始化
EF 會建立空白資料庫。 在本節中,我們將會新增一個方法,而該方法會在資料庫建立之後呼叫,以將測試資料填入資料庫。
EnsureCreated
方法將會用來自動建立資料庫。 在稍後的教學課程中,您將會了解到如何使用 Code First 移轉變更資料庫結構描述,而非卸除並重新建立資料庫,來處理模型的變更。
在 [Data] 資料夾中,使用下列程式碼建立名為 DbInitializer
的新類別:
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("2005-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
foreach (Student s in students)
context.Students.Add(s);
context.SaveChanges();
var courses = new Course[]
new Course{CourseID=1050,Title="Chemistry",Credits=3},
new Course{CourseID=4022,Title="Microeconomics",Credits=3},
new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
new Course{CourseID=1045,Title="Calculus",Credits=4},
new Course{CourseID=3141,Title="Trigonometry",Credits=4},
new Course{CourseID=2021,Title="Composition",Credits=3},
new Course{CourseID=2042,Title="Literature",Credits=4}
foreach (Course c in courses)
context.Courses.Add(c);
context.SaveChanges();
var enrollments = new Enrollment[]
new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
new Enrollment{StudentID=3,CourseID=1050},
new Enrollment{StudentID=4,CourseID=1050},
new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
new Enrollment{StudentID=6,CourseID=1045},
new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
foreach (Enrollment e in enrollments)
context.Enrollments.Add(e);
context.SaveChanges();
上述程式碼會檢查資料庫是否存在:
如果找不到資料庫;
- 將會建立資料庫並載入測試資料。 會將測試資料載入至陣列而非
List<T>
集合,以最佳化效能。
- 如果找到資料庫,則不會採取任何動作。
以下列程式碼來更新 Program.cs
:
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;
var context = services.GetRequiredService<SchoolContext>();
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>();
Program.cs
在應用程式啟動時會執行下列動作:
從相依性插入容器中取得資料庫內容執行個體。
呼叫 DbInitializer.Initialize
方法。
Initialize
方法完成時處置內容,如下列程式碼所示:
public static void Main(string[] args)
var host = CreateWebHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
var services = scope.ServiceProvider;
var context = services.GetRequiredService<SchoolContext>();
DbInitializer.Initialize(context);
catch (Exception ex)
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
host.Run();
第一次執行應用程式時,將建立資料庫並載入測試資料。 每當資料模型變更時:
刪除資料庫。
更新種子方法,並使用新的資料庫重新開始。
在之後的教學課程中,資料模型變更時就會修改資料庫,不必刪除和重新建立資料庫。 資料模型變更時不會遺失任何資料。
建立控制器和檢視
使用 Visual Studio 中的 Scaffolding 引擎來新增使用 EF 查詢和儲存資料的 MVC 控制器及檢視。
自動建立 CRUD 動作方法和檢視稱為 Scaffolding。
在 [方案總管] 中,以滑鼠右鍵按一下 Controllers
資料夾,然後選取 [新增] > [新增 Scaffold 項目]。
在 [新增 Scaffold] 對話方塊中:
- 選取 [使用 Entity Framework 執行檢視的 MVC 控制器]。
- Click Add. [新增使用 Entity Framework 執行檢視的 MVC 控制器] 對話方塊隨即出現:

- 在 [模型類別] 中,選取 [Student]。
- 在 [資料內容類別] 中,選取 [SchoolContext]。
- 接受預設的 StudentsController 作為名稱。
- Click Add.
Visual Studio Scaffolding 引擎會建立 StudentsController.cs
檔案及一組可以使用該控制器的檢視 (*.cshtml
檔案)。
請注意,控制器會接受 SchoolContext
作為建構函式的參數。
namespace ContosoUniversity.Controllers
public class StudentsController : Controller
private readonly SchoolContext _context;
public StudentsController(SchoolContext context)
_context = context;
ASP.NET Core 相依性插入會負責傳遞 SchoolContext
的執行個體給控制器。 您已在 Startup
類別中設定該項。
控制器含有一個 Index
動作方法,該方法會顯示資料庫中的所有學生。 方法會藉由讀取資料庫內容執行個體的 Students
屬性,來從 Students 實體集中取得學生的清單:
public async Task<IActionResult> Index()
return View(await _context.Students.ToListAsync());
教學課程稍後會說明此程式碼中的非同步程式設計元素。
Views/Students/Index.cshtml
檢視會在資料表中顯示此清單:
@model IEnumerable<ContosoUniversity.Models.Student>
ViewData["Title"] = "Index";
<h2>Index</h2>
<a asp-action="Create">Create New</a>
<table class="table">
<thead>
@Html.DisplayNameFor(model => model.LastName)
@Html.DisplayNameFor(model => model.FirstMidName)
@Html.DisplayNameFor(model => model.EnrollmentDate)
<th></th>
</thead>
<tbody>
@foreach (var item in Model) {
@Html.DisplayFor(modelItem => item.LastName)
@Html.DisplayFor(modelItem => item.FirstMidName)
@Html.DisplayFor(modelItem => item.EnrollmentDate)
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</tbody>
</table>
按 CTRL+F5 來執行專案,或從功能表選擇 [偵錯] > [啟動但不偵錯]。
按一下 [Students] 索引標籤來查看 DbInitializer.Initialize
方法插入的測試資料。 取決於您瀏覽器視窗的寬度,您可能會在頁面的頂端看到 Students
索引標籤連結,或是按一下位於右上角的導覽圖示來查看連結。
使用 [SQL Server 物件總管] (SSOX) 以在 Visual Studio 中檢視資料庫:
- 從 Visual Studio 中的 [檢視] 功能表選取 [SQL Server 物件總管]。
- 在 SSOX 中,選取 [(localdb)\MSSQLLocalDB] > [資料庫]。
- 選取
ContosoUniversity1
,這是 appsettings.json
檔案中連接字串內資料庫名稱的項目。
- 展開 [資料表] 節點以查看資料庫中的資料表。
*.mdf
和 *.ldf
資料庫檔案皆位於 C:\Users\<使用者名稱> 資料夾中。
因為應用程式啟動時執行的初始化運算式方法會呼叫 EnsureCreated
,所以您可以:
- 對
Student
類別進行變更。
- 刪除資料庫。
- 停止,然後啟動應用程式。 資料庫會自動重新建立,以符合變更。
例如,若將 EmailAddress
屬性新增到 Student
類別,重新建立的資料表中應會出現新的 EmailAddress
資料行。 檢視不會顯示新的 EmailAddress
屬性。
Conventions
為了讓 EF 建立完整資料庫所需撰寫的程式碼數量非常少,這是因為 EF 使用慣例的緣故:
DbSet
屬性的名稱會用於資料表名稱。 針對 DbSet
屬性並未參考的實體,實體類別名稱會用於資料表名稱。
- 實體屬性名稱會用於資料行名稱。
- 名為
ID
或 classnameID
的實體屬性會辨識為 PK 屬性。
- 如果屬性命名為
<
導覽屬性名稱><
PK 屬性名稱>
,則該屬性將解譯為 PK 屬性。 例如,StudentID
導覽屬性的 Student
,因為 Student
實體的 PK 是 ID
。 FK 屬性也可以命名為 <
主索引鍵屬性名稱>
。 例如 EnrollmentID
,因為 Enrollment
實體的 PK 是 EnrollmentID
。
慣例行為可以被覆寫。 例如,可以明確指定資料表名稱,如稍早在本教學課程中所示。 資料行名稱和任何屬性都可以設定為 PK 或 FK。
Asynchronous code
非同步程式設計是預設的 ASP.NET Core 和 EF Core 模式。
網頁伺服器的可用執行緒數量有限,而且在高負載情況下,可能會使用所有可用的執行緒。 發生此情況時,伺服器將無法處理新的要求,直到執行緒空出來。 使用同步程式碼,許多執行緒可能在實際上並未執行任何工作時受到占用,原因是在等候 I/O 完成。 使用非同步程式碼,處理程序在等候 I/O 完成時,其執行緒將會空出來以讓伺服器處理其他要求。 因此,非同步程式碼可讓伺服器資源更有效率地使用,而且伺服器可處理更多流量而不會造成延遲。
非同步程式碼雖然的確會在執行階段造成少量的負荷,但在低流量情況下,對效能的衝擊非常微小;在高流量情況下,潛在的效能改善則相當大。
在下列程式碼中,async
、Task<T>
、await
和 ToListAsync
都會讓程式碼以非同步方式執行。
public async Task<IActionResult> Index()
return View(await _context.Students.ToListAsync());
async
關鍵字會告訴編譯器為方法本體的一部分產生回呼,並自動建立傳回的 Task<IActionResult>
物件。
- 傳回類型
Task<IActionResult>
代表了正在進行的工作,其結果為 IActionResult
類型。
await
關鍵字會使編譯器將方法分割為兩部分。 第一個部分會與非同步啟動的作業一同結束。 第二個部分則會放入作業完成時呼叫的回呼方法中。
ToListAsync
是 ToList
擴充方法的非同步版本。
若要撰寫使用 EF 的非同步程式碼,請注意下列事項:
- 只有讓查詢或命令傳送至資料庫的陳述式,會以非同步方式執行。 其中包含,例如
ToListAsync
、SingleOrDefaultAsync
,以及 SaveChangesAsync
。 其中不包含,例如:僅變更 IQueryable
的陳述式,例如 var students = context.Students.Where(s => s.LastName == "Davolio")
。
- EF 內容在執行緒中並不安全:不要嘗試執行多個平行作業。 當您呼叫任何 async EF 方法時,請一律使用
await
關鍵字。
- 若要充分利用非同步程式碼帶來的效能優點,若使用的任何程式庫封裝會呼叫任何可能會傳送查詢到資料庫的 EF 方法,請確保該程式庫封裝也是使用非同步程式碼。
如需在 .NET 中非同步程式設計的詳細資訊,請參閱非同步總覽。
限制擷取的實體
如需限制從查詢傳回的實體數目資訊,請參閱 效能考量。
Entity Framework Core 的 SQL 記錄
記錄組態通常是由 Logging
檔案的 appsettings.{Environment}.json
區段所提供。 若要記錄 SQL 陳述式,請將 "Microsoft.EntityFrameworkCore.Database.Command": "Information"
新增至 appsettings.Development.json
檔案:
"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": "*"
使用上述 JSON 時,SQL 陳述式會顯示在命令列和 Visual Studio 輸出視窗中。
如需詳細資訊,請參閱 登入 .NET 和 ASP.NET Core 和此 GitHub 問題。
若要了解如何執行基本的 CRUD (建立、讀取、更新、刪除) 作業,請前往下一個教學課程。
實作基本的 CRUD 功能
本教學課程可讓您了解具有控制器和檢視的 ASP.NET Core MVC 和 Entity Framework Core。
Razor Pages 是替代的程式設計模型。 針對新的開發,我們建議您搭配控制器與檢視在 MVC 上使用 Razor Pages。 請參閱 Razor Pages 版的本教學課程。 每個教學課程都涵蓋其他教學課程為涵蓋的一些內容:
此 MVC 教學課程中的一些內容具有 Razor Pages 教學課程未包含的內容:
- 在資料模型中實作繼承
- 執行原始 SQL 查詢
- 使用動態 LINQ 來簡化程式碼
Razor Pages 教學課程中的一些內容具有此教學課程未包含的內容:
- 使用 Select 方法來載入相關資料
- EF 的最佳做法。
Contoso 大學範例 Web 應用程式示範如何使用 Entity Framework (EF) Core 2.2 和 Visual Studio 2019 來建立 ASP.NET Core 2.2 MVC Web 應用程式。
此教學課程尚未升級至 ASP.NET Core 3.1。 已為 .NET 5 中的 ASP.NET Core 進行更新。
這個範例應用程式是虛構的 Contoso 大學網站。 其中包括的功能有學生入學許可、課程建立、教師指派。 這是說明如何從零開始建立 Contoso 大學範例應用程式教學課程系列中的第一頁。
Prerequisites
.NET Core SDK 2.2
Visual Studio 2019 和下列工作負載:
ASP.NET 與網頁程式開發工作負載
.NET Core 跨平台開發工作負載
Troubleshooting
如果您遭遇無法解決的問題,將您的程式碼與已完成的專案作比較,通常可以找到解答。 如需常見錯誤和如何解決這些問題的清單,請參閱 本系列最後一個教學課程中的疑難排解一節。 如果您在那裡找不到所需的資訊,可以在 StackOverflow.com 上張貼關於 ASP.NET Core 或 EF Core 的問題。
這是 10 個教學的系列課程,當中的每一個課程都是建置於先前教學課程的成果上。 成功完成每一個教學課程後,請儲存專案的複本。 如果您遇到問題,您可以從上一個教學課程來重新開始,而不需從系列的一開始從頭來過。
Contoso 大學 Web 應用程式
您在這些教學課程中會建置的應用程式為一個簡單的大學網站。
使用者可以檢視和更新學生、課程和教師資訊。 以下是您會建立的幾個畫面。
等候 [新增 ASP.NET Core Web 應用程式] 對話方塊出現。
選取 [.NET Core]、[ASP.NET Core 2.2] 和 [Web 應用程式 (Model-View-Controller)] 範本。
確認 [驗證] 已設為 [No Authentication] (無驗證)。
Select OK
開啟 Views/Shared/_Layout.cshtml
,然後進行下列變更:
將每個出現的 "ContosoUniversity" 都變更為 "Contoso University"。 共有三個發生次數。
為 [About]、[Students]、[Courses]、[Instructors] 及 [Departments] 新增功能表項目,並刪除 [Privacy]Privacy 功能表項目。
所做的變更已醒目提示。
<!DOCTYPE html>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Contoso University</title>
<environment include="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
crossorigin="anonymous"
integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
</environment>
<link rel="stylesheet" href="~/css/site.css" />
</head>
<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-controller="Home" asp-action="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-controller="Home" asp-action="Index">Home</a>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="About">About</a>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Students" asp-action="Index">Students</a>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Courses" asp-action="Index">Courses</a>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Departments" asp-action="Index">Departments</a>
</header>
<div class="container">
<partial name="_CookieConsentPartial" />
<main role="main" class="pb-3">
@RenderBody()
</main>
<footer class="border-top footer text-muted">
<div class="container">
© 2019 - Contoso University - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</footer>
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
</environment>
<environment exclude="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"
asp-fallback-src="~/lib/jquery/dist/jquery.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
</script>
</environment>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>
在 Views/Home/Index.cshtml
中用下列程式碼取代檔案內容,以使用關於此應用程式的文字來取代關於 ASP.NET 和 MVC 的文字:
ViewData["Title"] = "Home Page";
<div class="jumbotron">
<h1>Contoso University</h1>
<div class="row">
<div class="col-md-4">
<h2>Welcome to Contoso University</h2>
Contoso University is a sample application that
demonstrates how to use Entity Framework Core in an
ASP.NET Core MVC web application.
<div class="col-md-4">
<h2>Build it from scratch</h2>
<p>You can build the application by following the steps in a series of tutorials.</p>
<p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial »</a></p>
<div class="col-md-4">
<h2>Download it</h2>
<p>You can download the completed project from GitHub.</p>
<p><a class="btn btn-default" href="https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/data/ef-mvc/intro/samples/cu-final">See project source code »</a></p>
按 CTRL+F5 來執行專案,或從功能表選擇 [偵錯] > [啟動但不偵錯]。 您會看到首頁,其中包含您將在這些教學課程中建立之頁面的索引標籤。
關於 EF Core NuGet 封裝
若要將 EF Core 支援新增至專案,請安裝您欲使用資料庫的提供者。 本教學課程使用 SQL Server,其提供者套件為 Microsoft.EntityFrameworkCore.SqlServer。 此套件包含在 Microsoft.AspNetCore.App metapackage 中,因此您不需要參考該套件。
EF SQL Server 套件及其相依性 (Microsoft.EntityFrameworkCore
及 Microsoft.EntityFrameworkCore.Relational
) 提供了 EF 的執行階段支援。 您會在稍後的移轉教學課程中新增工具套件。
如需其他 Entity Framework Core 可用之資料庫提供者的資訊,請參閱資料庫提供者。
建立資料模型
接下來您會為 Contoso 大學應用程式建立實體類別。 您會從下列三個實體開始。
在 Student
和 Enrollment
實體之間存在一對多關聯性,Course
與 Enrollment
實體之間也存在一對多關聯性。 換句話說,一位學生可以註冊並參加任何數目的課程,而一個課程也可以有任何數目的學生註冊。
在下節中,您會為這些實體建立各自的類別。
Student 實體
在 [Models] 資料夾中,建立一個名為 Student.cs
的類別檔案,然後使用下列程式碼取代範本程式碼。
using System;
using System.Collections.Generic;
namespace ContosoUniversity.Models
public class Student
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
ID
屬性會成為資料庫資料表中的主索引鍵資料行,並對應至這個類別。 Entity Framework 預設會將名為 ID
或 classnameID
的屬性解譯為主索引鍵。
Enrollments
屬性為導覽屬性。 導覽屬性會保留與此實體相關的其他實體。 在這個案例中,Enrollments
的 Student entity
屬性會保有與該 Enrollment
實體相關的所有 Student
實體。 換句話說,若資料庫中 Student
資料列有兩個相關的Enrollment
資料列 (包含該學生於其 StudentID 外部索引鍵資料行中主索引鍵值的資料列),該 Student
實體的 Enrollments
導覽屬性便會包含這兩個 Enrollment
實體。
若導覽屬性可保有多個實體 (例如在多對多或一對多關聯性中的情況),其類型必須為一個清單,使得實體可以在該清單中新增、刪除或更新,例如 ICollection<T>
。 您可以指定 ICollection<T>
或如 List<T>
或 HashSet<T>
等類型。 若您指定了 ICollection<T>
,EF 會根據預設建立一個 HashSet<T>
集合。
Enrollment 實體
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public Course Course { get; set; }
public Student Student { get; set; }
EnrollmentID
屬性將為主索引鍵。此實體會使用 classnameID
模式,而非您在 ID
實體中所見到的自身 Student
。 通常您會選擇一個模式,然後在您整個資料模型中使用此模式。 在這裡,此變化僅作為向您展示使用不同模式之用。 在稍後的教學課程中,您會了解使用沒有 classname 的識別碼可讓在資料模型中實作繼承變得更為簡單。
Grade
屬性為 enum
。 問號之後的 Grade
類型宣告表示 Grade
屬性可為 Null。 為 Null 的成績不同於成績為零:Null 表示成績未知或尚未指派。
StudentID
屬性是外部索引鍵,對應的導覽屬性是 Student
。
Enrollment
實體與一個 Student
實體關聯,因此屬性僅能保有單一 Student
實體 (不像您先前看到的 Student.Enrollments
導覽屬性可保有多個 Enrollment
實體)。
CourseID
屬性是外部索引鍵,對應的導覽屬性是 Course
。 一個 Enrollment
實體與一個 Course
實體建立關聯。
Entity Framework 會將名為 <navigation property name><primary key property name>
的屬性解譯為外部索引鍵屬性 (例如 StudentID
導覽屬性的 Student
,因為 Student
實體的主索引鍵為 ID
)。 外部索引鍵屬性也可以簡單的命名為 <primary key property name>
(例如 CourseID
,因為 Course
實體的主索引鍵為 CourseID
)。
Course 實體
在 [Models] 資料夾中,建立 Course.cs
,然後使用下列程式碼取代現有的程式碼:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace ContosoUniversity.Models
public class Course
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
Enrollments
屬性為導覽屬性。
Course
實體可以與任何數量的 Enrollment
實體相關。
我們會在此系列DatabaseGenerated
中進一步討論 屬性。 基本上,此屬性可讓您為課程輸入主索引鍵,而非讓資料庫產生它。
建立資料庫內容
為指定資料模型協調 Entity Framework 功能的主要類別便是資料庫內容類別。 若要建立此類別,您可以從 Microsoft.EntityFrameworkCore.DbContext
類別來衍生。 在您的程式碼中,您會指定資料模型中包含哪些實體。 您也可以自訂某些 Entity Framework 行為。 在此專案中,類別命名為 SchoolContext
。
在專案資料夾中,建立名為 Data 的資料夾。
在 [Data] 資料夾中,建立名為 SchoolContext.cs
的新類別檔案,然後使用下列程式碼取代範本程式碼:
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
public class SchoolContext : DbContext
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
程式碼會為每一個實體集建立 DbSet
屬性。 在 Entity Framework 詞彙中,實體集通常會對應至資料庫資料表,而實體則對應至資料表中的資料列。
您可以省略 DbSet<Enrollment>
及 DbSet<Course>
陳述式,其結果也會是相同的。 Entity Framework 會隱含它們,因為 Student
實體參考了 Enrollment
實體;而 Enrollment
實體參考了 Course
實體。
資料庫建立時,EF 會建立和 DbSet
屬性名稱相同的資料表。 集合的屬性名稱通常都是複數 (Students 而非 Student),但許多開發人員會為了資料表名稱究竟是否該是複數型態而爭論。 在此系列教學課程中,您會藉由指定 DbContext 中的單數資料表名稱來覆寫預設行為。 若要完成這項操作,請在最後一個 DbSet 屬性後方新增下列醒目提示程式碼。
using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;
namespace ContosoUniversity.Data
public class SchoolContext : DbContext
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
建置專案以檢查編譯器錯誤。
註冊 SchoolContext
根據預設,ASP.NET Core 會實作相依性插入。 服務 (例如 EF 資料庫內容) 是在應用程式啟動期間使用相依性插入來註冊。 接著,會透過建構函式參數,針對需要這些服務的元件 (例如 MVC 控制器) 來提供服務。 您會在此教學課程的稍後看到取得內容執行個體的控制器建構函式。
若要將 SchoolContext
註冊為服務,請開啟 Startup.cs
,並將醒目標示的程式碼新增至 ConfigureServices
方法。
public void ConfigureServices(IServiceCollection services)
services.Configure<CookiePolicyOptions>(options =>
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
services.AddDbContext<SchoolContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc();
連接字串的名稱,會透過呼叫 DbContextOptionsBuilder
物件上的方法來傳遞至內容。 作為本機開發之用,ASP.NET Core 設定系統會從 appsettings.json
檔案讀取連接字串。
為 using
和 ContosoUniversity.Data
命名空間新增 Microsoft.EntityFrameworkCore
陳述式,然後建置專案。
using ContosoUniversity.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;
開啟 appsettings.json
檔案並新增連接字串,如下列範例所示。
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
SQL Server Express LocalDB (本地資料庫)
連接字串會指定 SQL Server LocalDB 資料庫。 LocalDB 是輕量版的 SQL Server Express Database Engine,旨在用於應用程式開發,而不是生產用途。 LocalDB 會依需求啟動,並以使用者模式執行,因此沒有複雜的組態。 LocalDB 預設會在 目錄中建立 C:/Users/<user>
資料庫檔案。
使用測試資料將 DB 初始化
Entity Framework 會為您建立空白資料庫。 在本節中,您會撰寫一個方法,該方法會在資料庫建立之後呼叫,以將測試資料填入資料庫。
在此您將使用 EnsureCreated
方法來自動建立資料庫。 在稍後的教學課程中,您將會了解到如何使用 Code First 移轉變更資料庫結構描述,而非卸除並重新建立資料庫,來處理模型的變更。
在 [Data] 資料夾中,建立一個名為 DbInitializer.cs
的新類別檔案,使用下列程式碼取代範本程式碼。這些程式碼會在需要的時候建立資料庫,並將測試資料載入至新的資料庫。
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("2005-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
foreach (Student s in students)
context.Students.Add(s);
context.SaveChanges();
var courses = new Course[]
new Course{CourseID=1050,Title="Chemistry",Credits=3},
new Course{CourseID=4022,Title="Microeconomics",Credits=3},
new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
new Course{CourseID=1045,Title="Calculus",Credits=4},
new Course{CourseID=3141,Title="Trigonometry",Credits=4},
new Course{CourseID=2021,Title="Composition",Credits=3},
new Course{CourseID=2042,Title="Literature",Credits=4}
foreach (Course c in courses)
context.Courses.Add(c);
context.SaveChanges();
var enrollments = new Enrollment[]
new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
new Enrollment{StudentID=3,CourseID=1050},
new Enrollment{StudentID=4,CourseID=1050},
new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
new Enrollment{StudentID=6,CourseID=1045},
new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
foreach (Enrollment e in enrollments)
context.Enrollments.Add(e);
context.SaveChanges();
程式碼會檢查資料庫中是否有任何學生。若沒有的話,它便會假設資料庫是新的資料庫,因此需要植入測試資料。 會將測試資料載入至陣列而非 List<T>
集合,以最佳化效能。
在 Program.cs
中,修改 Main
方法來在應用程式啟動期間執行下列動作:
- 從相依性插入容器中取得資料庫內容執行個體。
- 呼叫種子方法,並將其傳遞給內容。
- 種子方法完成時處理內容。
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;
var context = services.GetRequiredService<SchoolContext>();
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>();
在您首次執行應用程式時,資料庫便會建立並植入測試資料。 每當您變更資料模型時:
- 刪除資料庫。
- 更新種子方法,並使用相同方法以新的資料庫重新開始。
在稍後的教學課程中,您會了解如何在資料模型變更時修改資料庫,而不需要刪除和重新建立它。
建立控制器和檢視
在本節中,我們將會使用 Visual Studio 中的 Scaffolding 引擎來新增使用 EF 查詢和儲存資料的 MVC 控制器及檢視。
自動建立 CRUD 動作方法和檢視稱為 Scaffolding。 Scaffolding 與產生程式碼不同。Scaffold 程式碼是一個開始點,使得您可以修改它以符合您的需求,然而您通常不會去修改產生的程式碼。 當您需要自訂產生的程式碼時,您會使用部分類別,或者您會在事務變更時重新產生程式碼。
- 以滑鼠右鍵按一下 [方案總管] 中的 [Controllers] 資料夾,然後選取 [新增] > [新增 Scaffold 項目]。
- 在 [新增 Scaffold] 對話方塊中:
- 選取 [使用 Entity Framework 執行檢視的 MVC 控制器]。
- Click Add. [新增使用 Entity Framework 執行檢視的 MVC 控制器] 對話方塊隨即出現:

- 在 [模型類別] 中,選取 [Student]。
- 在 [資料內容類別] 中,選取 [SchoolContext]。
- 接受預設的 StudentsController 作為名稱。
- Click Add.
Visual Studio Scaffolding 引擎會建立 StudentsController.cs
檔案及一組可以使用該控制器的檢視 (.cshtml
檔案)。
請注意,控制器會接受 SchoolContext
作為建構函式的參數。
namespace ContosoUniversity.Controllers
public class StudentsController : Controller
private readonly SchoolContext _context;
public StudentsController(SchoolContext context)
_context = context;
ASP.NET Core 相依性插入會負責傳遞 SchoolContext
的執行個體給控制器。 該項已在 Startup.cs
檔案中設定。
控制器含有一個 Index
動作方法,該方法會顯示資料庫中的所有學生。 方法會藉由讀取資料庫內容執行個體的 Students
屬性,來從 Students 實體集中取得學生的清單:
public async Task<IActionResult> Index()
return View(await _context.Students.ToListAsync());
您會在教學課程的稍後學習到此程式碼中的非同步程式設計項目。
Views/Students/Index.cshtml
檢視會在資料表中顯示此清單:
@model IEnumerable<ContosoUniversity.Models.Student>
ViewData["Title"] = "Index";
<h2>Index</h2>
<a asp-action="Create">Create New</a>
<table class="table">
<thead>
@Html.DisplayNameFor(model => model.LastName)
@Html.DisplayNameFor(model => model.FirstMidName)
@Html.DisplayNameFor(model => model.EnrollmentDate)
<th></th>
</thead>
<tbody>
@foreach (var item in Model) {
@Html.DisplayFor(modelItem => item.LastName)
@Html.DisplayFor(modelItem => item.FirstMidName)
@Html.DisplayFor(modelItem => item.EnrollmentDate)
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</tbody>
</table>
按 CTRL+F5 來執行專案,或從功能表選擇 [偵錯] > [啟動但不偵錯]。
按一下 [Students] 索引標籤來查看 DbInitializer.Initialize
方法插入的測試資料。 取決於您瀏覽器視窗的寬度,您可能會在頁面的頂端看到 Students
索引標籤連結,或是按一下位於右上角的導覽圖示來查看連結。
檢視資料庫
當您啟動應用程式時,DbInitializer.Initialize
方法會呼叫 EnsureCreated
。 EF 看到不存在任何資料庫,於是便建立了一個資料庫,接著 Initialize
方法程式碼的剩餘部分便會將資料填入資料庫。 您可以使用 [SQL Server 物件總管 (SSOX) 來在 Visual Studio 中檢視資料庫。
關閉瀏覽器。
若 SSOX 視窗尚未開啟,請從 Visual Studio 中的 [檢視] 功能表選取它。
在 SSOX 中,按一下 [(localdb)\MSSQLLocalDB] > [Databases],然後按一下位於 appsettings.json
檔案中連接字串內資料庫名稱的項目。
展開 [資料表] 節點以查看資料庫中的資料表。
.mdf 和 .ldf 資料庫檔案位於 C:\Users<使用者名稱> 資料夾中。
因為您在應用程式啟動時執行的初始設定式方法中呼叫了 EnsureCreated
,您現在可以對 Student
類別進行變更、刪除資料庫、重新執行應用程式,資料庫會自動重新建立以符合您所作出的變更。 例如,若您將一個 EmailAddress
屬性新增到 Student
類別,您便會在重新建立的資料表中看到新的 EmailAddress
資料行。
Conventions
為了讓 Entity Framework 能夠建立一個完整資料庫,您所需要撰寫的程式碼非常少,多虧了慣例的使用及 Entity Framework 所做出的假設。
DbSet
屬性的名稱會用於資料表名稱。 針對 DbSet
屬性並未參考的實體,實體類別名稱會用於資料表名稱。
- 實體屬性名稱會用於資料行名稱。
- 命名為 ID 或 classnameID 的實體屬性,會辨識為主索引鍵屬性。
- 如果屬性命名為 <導覽屬性名稱><主索引鍵屬性名稱>,系統就會將該屬性解譯為外部索引鍵屬性 (例如,若為
StudentID
導覽屬性則為 Student
,因為 Student
實體的主索引鍵是 ID
)。 外部索引鍵屬性也可以直接命名為 <主索引鍵屬性名稱> (例如 EnrollmentID
,因為 Enrollment
實體的主索引鍵為EnrollmentID
)。
慣例行為可以被覆寫。 例如,您可以明確指定資料表名稱,如稍早在本教學課程中您所見到的。 您可以設定資料行名稱以及將任何屬性設為主索引鍵或外部索引鍵,如同您在本系列稍後的教學課程中所見。
Asynchronous code
非同步程式設計是預設的 ASP.NET Core 和 EF Core 模式。
網頁伺服器的可用執行緒數量有限,而且在高負載情況下,可能會使用所有可用的執行緒。 發生此情況時,伺服器將無法處理新的要求,直到執行緒空出來。 使用同步程式碼,許多執行緒可能在實際上並未執行任何工作時受到占用,原因是在等候 I/O 完成。 使用非同步程式碼,處理程序在等候 I/O 完成時,其執行緒將會空出來以讓伺服器處理其他要求。 因此,非同步程式碼可讓伺服器資源更有效率地使用,而且伺服器可處理更多流量而不會造成延遲。
非同步程式碼雖然的確會在執行階段造成少量的負荷,但在低流量情況下,對效能的衝擊非常微小;在高流量情況下,潛在的效能改善則相當大。
在下列程式碼中,async
關鍵字、Task<T>
傳回值、await
關鍵字和ToListAsync
方法使程式碼以非同步方式執行。
public async Task<IActionResult> Index()
return View(await _context.Students.ToListAsync());
async
關鍵字會告訴編譯器為方法本體的一部分產生回呼,並自動建立傳回的 Task<IActionResult>
物件。
- 傳回類型
Task<IActionResult>
代表了正在進行的工作,其結果為 IActionResult
類型。
await
關鍵字會使編譯器將方法分割為兩部分。 第一個部分會與非同步啟動的作業一同結束。 第二個部分則會放入作業完成時呼叫的回呼方法中。
ToListAsync
是 ToList
擴充方法的非同步版本。
當您在撰寫使用 Entity Framework 的非同步程式碼時,請注意下列事項:
- 只有讓查詢或命令傳送至資料庫的陳述式,會以非同步方式執行。 其中包含,例如
ToListAsync
、SingleOrDefaultAsync
,以及 SaveChangesAsync
。 其中不包含,例如:僅變更 IQueryable
的陳述式,例如 var students = context.Students.Where(s => s.LastName == "Davolio")
。
- EF 內容在執行緒中並不安全:不要嘗試執行多個平行作業。 當您呼叫任何 async EF 方法時,請一律使用
await
關鍵字。
- 若您想要充分利用非同步程式碼帶來的效能優點,請確保任何您正在使用的程式庫 (例如分頁) 也使用了非同步 (若它們有呼叫任何可能會傳送查詢到資料庫的 Entity Framework 方法的話)。
如需在 .NET 中非同步程式設計的詳細資訊,請參閱非同步總覽。
Next steps
若要了解如何執行基本的 CRUD (建立、讀取、更新、刪除) 作業,請前往下一個教學課程。
實作基本的 CRUD 功能