ASP.NET Core Razor Pages 使用 EntityFramework Core 将枚举映射为字符串 - 第一部分





5.00/5 (5投票s)
创建初始对象模型和数据库,
引言
本系列文章演示了如何通过 EntityFramework Core 2.1 (EF) 将 C# enum
值映射到数据库表中的 string
值。文章讨论了在与应用程序实体的一对多和多对多关系中 enum
值的映射。这一切都将在 ASP.NET Core Razor Pages 应用程序的上下文中进行。
EF 是一个对象关系映射器 (ORM)。在这种示例应用程序中,存在两个“世界”。一个是以 C# 对象模型形式存在的对象世界。另一个是以关系型数据库(如 Microsoft SQL Server)形式存在的关系世界。这两个世界并不相互一致。ORM(如 EntityFramework)的功能就是连接这两个世界并促进它们之间的数据传输。
在第一部分中,我们将回顾以下内容:
- 示例应用程序的概念和工作对象模型
- 创建包含 ASP.NET Core Razor Pages 项目的 Visual Studio 2017 (VS2017) 解决方案
- 在 C# 中初始创建应用程序对象模型,即
Customer
类 - 设置应用程序用户界面 (UI) 布局和主页
- 通过
QuantumDbContext
类使用 EF 初始化脚手架化 Customer 的 CRUD (Create-Read-Update-Delete) 页面。这包括在localdb
SQL Server 实例中创建应用程序数据库。 - 介绍为与 EF 交互的对象模型类配置单独的类,以方便数据库表的设计
- 实现 _Customers/Index_ 页面
第二部分。 完成 Customer
的 CRUD 功能
第三部分。 创建 Project
和 ProjectState
实体,并在 ProjectState
和 Project
之间实现一对多关系
第四部分。 添加 Skill
实体 (Skill enum
, SkillTitle
和 ProjectSkill
),并在 Project
和 Skill
之间实现多对多关系
背景
枚举是一种包含一组命名常量的数据类型。常量的名称通常是助记符。助记符被定义为一种辅助记忆的工具。然而,在枚举中倾向于使用助记符作为常量名称。作为开发者,我可能使用的名称对用户来说是晦涩难懂的。从命令行界面转向图形用户界面 (GUI) 的部分动机源于使用助记符作为命令。此外,enum
值的默认映射是整数。整数值的含义违背了助记符的概念。
使用 enum
有一些优点。第一个是命名常量的集合相对较小,便于自验证。如果我们尝试使用未在 enum
中定义的值,则会生成错误。
此处实现的示例应用程序是为虚构的工程技术公司 Quantum Engineering Technologies 准备的。Quantum 主要服务于石油、天然气和化工行业。关键实体是 Customer
。Quantum 服务于许多 Customers
。每个 Customer
又拥有多个 Projects
。每个 Project
都有一个在 enum
ProjectState
中定义的的状态。ProjectState
和 Projects
之间存在一对多关系。ProjectState enum
允许定义一个状态机来帮助管理 Project
工作流。项目状态机超出了本文的范围。
一个项目需要多个 Skills
。此应用程序定义了一个 Skill enum
。Projects
和 Skills
之间存在多对多关系。这些关系在下面的图中表示,该图显示了 C# 中的概念对象模型。
概念对象模型
枚举包含本质上是静态的数据。这些值是助记符,尤其是在 Skill enum
中。大多数用户并不轻易识别“CtrlE”是控制工程师,“DataSci”是数据科学家。这里的一个目标是实现一个方案,以一种用户更容易理解的方式在用户界面 (UI) 中呈现这些值。为此,我们使用下面的工作对象模型。
工作对象模型
ProjectStateDescription
实体将 ProjectState
中的 enum
值映射到描述 Project
状态的 Description string
。SkillTitle
实体将 Skill
中的 enum
值映射到 SkillTitle
中的 Title string
。Project
和 Skill
之间的多对多关系通过 ProjectSkill
实体来表达。稍后我们将讨论此对象模型的重要性。
开发环境
示例解决方案是在以下环境中创建的:
- Visual Studio 2017 (VS2017)
- ASP.NET Core 2.1
- Entity Framework Core v.2.1.4
- NuGet 包管理器 v.4.6.0
- SQL Server LocalDb
- SQL Server Management Studio
Using the Code
我们首先创建一个空的 VS2017 解决方案,名为 QuantumEngSolution
。有一个创建项目的选项,但无论如何都会创建一个解决方案。出于个人风格,我更喜欢显式创建和命名解决方案。
创建 QuantumEngSolution,一个空的 Vs2017 解决方案
点击“OK”继续。接下来,添加一个 ASP.NET Core 2.1 Web 应用程序,名为 QuantumWeb
。
将 QuantumWeb ASP.NET Core Web 应用程序添加到 QuantumEngSolution
将项目配置为 ASP.NET Core 2.1 Web 应用程序
这将配置应用程序,使其不使用身份验证并使用 HTTPS。如果在调试和测试中遇到问题,您将需要启用 VS2017 安装中的 HTTPS。(请参阅此链接。)
点击“OK”后,初始的解决方案资源管理器如下图所示:
初始解决方案资源管理器
接下来,我们在 QuantumWeb
项目中添加一个新文件夹,名为 _Model_。此文件夹将包含我们对象模型中的文件。对于较大的应用程序,我们将创建一个类库项目来保存对象模型。这样做符合关注点分离的实践,并有助于在多个应用程序中使用对象模型。但是,由于这是一个演示示例,我们将把对象模型保留在同一个项目中。
现在,我们将开始在 _Model_ 文件夹中创建模型类,从 Customer
类开始。
创建 ~QuantumWeb\Model\Customer.cs
初始 Customer 类
namespace QuantumWeb.Model
{
/// <summary>
/// Customer Class
/// </summary>
public class Customer
{
#region Constructors
/// <summary>
/// Parameter-less Constructor
/// </summary>
/// <remarks>
/// Required for scaffolding the UI
/// </remarks>
public Customer()
{
} // end public Customer()
#endregion // Constructors
/// <summary>
/// Customer Identifier, primary key
/// </summary>
public int CustomerId { get; set; }
/// <summary>
/// Customer Name
/// </summary>
public string CustomerName { get; set; }
/// <summary>
/// Primary Customer Contact
/// </summary>
public string CustomerContact { get; set; }
/// <summary>
/// Customer Contact Phone Number
/// </summary>
public string CustomerPhone { get; set; }
/// <summary>
/// Customer Contact Email Address
/// </summary>
public string CustomerEmail { get; set; }
} // end public class Customer
} // end namespace QuantumWeb.Model
开始构建 UI 和数据访问
现在我们有了一个对象模型的开端,我们可以开始构建用户界面 (UI) 和数据访问功能。ASP.NET Razor Pages 可以配置为使用布局页面。解决方案资源管理器中的主布局页面如下图所示。
编辑主布局页面
初始 _Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Quantum Application</title>
<environment include="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet"
href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position"
asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse"
data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-page="/Index" class="navbar-brand">Quantum Web Application</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-page="/Index">Home</a></li>
<li><a asp-page="/About">About</a></li>
<li><a asp-page="/Contact">Contact</a></li>
<li><a asp-page="/Customers">
Customers</a></li> <!-- Link to Customer pages -->
</ul>
</div>
</div>
</nav>
<partial name="_CookieConsentPartial" />
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© 2018 - Quantum Engineering & Technologies</p>
</footer>
</div>
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment exclude="Development">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("Scripts", required: false)
</body>
</html>
接下来,我们创建 Customers
Razor Pages 并设置数据访问。VS2017 提供了一种方法来组合 Customers
的 UI 的脚手架和设置以及数据访问的初始化。右键单击 _Pages\Customers_ 文件夹,然后在弹出菜单中选择“Add”,接着在下一个弹出菜单中选择“New Scaffolded Item...”。
脚手架化 Customer Razor Pages
将显示一个 Razor Page 脚手架选项对话框。选择“Razor Pages using Entity Framework (CRUD)”选项。
选择“Razor Pages using Entity Framework (CRUD)”
这将配置一组 Razor Pages,通过 EF 在数据库中创建、读取、更新和删除 (CRUD) Customers。
配置 Customer Razor Pages - 创建 QuantumDbContext
点击每个对话框中的“Add”来构建解决方案并配置 Razor Pages 和 EF。_Viewstart.cshtml_ 文件指定了使用 _Layout.cshtml_ 作为默认布局。
_Viewstart.cshtml
@{
Layout = "_Layout";
}
使用 CRUD Pages 选项进行的脚手架化会在项目中产生许多更改。
脚手架化 Customer Pages 后的解决方案资源管理器
我们首先讨论修改和创建的文件。生成的代码存在一些问题,我们将在稍后讨论。
修改后的 appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"QuantumDbContext": "Server=(localdb)\\mssqllocaldb;
Database=QuantumDbContext-268e3954-a42e-460a-97a2-cff0a2cb9dd3;
Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
脚手架过程向应用程序设置添加了一个“ConnectionStrings
”属性。这表明将在 localdb
SQL Server 实例上创建一个名为 QuantumDbContext-268e3954-a42e-460a-97a2-cff0a2cb9dd3
的数据库。脚手架从指定的数据上下文名称 QuantumDbContext
生成了一个默认名称。此数据库将用于初始开发和测试。它不适用于生产环境。
修改后的 Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using QuantumWeb.Models;
namespace QuantumWeb
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a
// given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// The application startup specifies SQL Server and the database specified in the
// appsettings.json file
services.AddDbContext<QuantumDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("QuantumDbContext")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request
// pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
}
}
Startup
类包含在应用程序启动时执行的代码。其细节超出了本文的范围。详细讨论可以在 Microsoft 文档 此处找到。上面粗体显示的是重要行。这里,启动代码引用了 _appsetting.json_ 文件中的 ConnectionString
,并告诉 Entity Framework 如何查找数据库。
生成的 Pages\Index.cshtml
@page
@model IndexModel
@{
ViewData["Title"] = "Quantum Engineering & Technologies";
}
<div class="jumbotron">
<h1>Quantum Engineering & Technologies</h1>
<p>
This is a sample application for a fictitious engineering and technology company.
</p>
</div>
<div class="row">
<div>
<h2>Application illustrates</h2>
<ul>
<span style="display: inline !important; float: none; background-color: rgb(251, 237, 187);
color: rgb(0, 0, 0); font-family: Consolas,"Courier New",Courier,mono; font-size: 12px;
font-size-adjust: none; font-stretch: 100%; font-style: normal; font-variant: normal; font-weight: 400;
letter-spacing: normal; line-height: normal; orphans: 2; text-align: left; text-decoration: none;
text-indent: 0px; text-shadow: none; text-transform: none; -webkit-text-stroke-width: 0px;
white-space: pre; word-spacing: 0px;">
<li>Sample pages using ASP.NET Core Razor Pages</li></span>
<li>Entity Framework Core (v. 2.1.4 used here)</li>
<li>
Use of C# enumerations with members expressed in database as
strings as opposed to numbers
</li>
<li>One-to-many and many-to-many mapping between entities and enumerations</li>
<li>Use of the Fluent API and IEntityTypeConfiguration classes for configuration</li>
<li>
Theming using <a href="https://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a>
</li>
</ul>
</div>
</div>
我们用上面显示的 HTML 替换了 _Pages\Index_ 页面。它提供了一些关于示例演示的信息。关键项是第一行的“@page
” string
。这表明这是一个 Razor Page。
生成的 Pages\Index.cshtml.cs
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace QuantumWeb.Pages
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}
每个 Razor Page 由一个 _cshtml_ 文件(定义了在布局中渲染的 UI)和一个 _cshtml.cs_ 文件(包含处理 HTTP 命令 GET
和 POST
的 C# 代码)组成。_cshtml.cs_ 文件类似于 WebForm 的代码隐藏。然而,Razor Page 的行为更像 Model-View-Controller (MVC) 模式。您可以在 此处阅读有关比较 Razor Pages 和 MVC 的更多信息。
生成的 QuantumDbContext 类
using Microsoft.EntityFrameworkCore;
using QuantumWeb.Model;
namespace QuantumWeb.Models // Error!!!
{
public class QuantumDbContext : DbContext
{
public QuantumDbContext (DbContextOptions<QuantumDbContext> options)
: base(options)
{
} // end public QuantumDbContext (DbContextOptions<QuantumDbContext> options)
#region DbSets
public DbSet<Customer> Customer { get; set; }
#endregion // DbSets
} // end public class QuantumDbContext : DbContext
} // end namespace QuantumWeb.Models
这显示了脚手架过程中生成的初始数据上下文类 QuantumDbContext
,并添加了一些注释以提高可读性,并避免在文件变得更复杂时出现编辑错误。另外,请注意命名空间中的“Error!!!
”注释。稍后我们将解决这个问题。在 EF Core 中,我们必须有一个派生自 Microsoft.EntityFrameworkCore.DbContext
的类。
对于旧版本的 EntityFramework
,这很容易在 Class
Library 中完成。随着我们的进行,我们将使用 EntityFramework
Migrations 来创建和更新数据库。截至本文撰写之时,在 Class
Library 中使用 EntityFramework
Core migrations 存在一个问题。如果我们想要轻松地将数据访问功能分离到单独的项目并使用 migrations,最好使用数据访问服务来完成。目前,我们将放弃该选项。
DbContext
基类包含促进与数据库交互以及对象模型和关系模型之间相关转换的方法。随着开发的进行,我们将向此类添加内容。
就目前的数据上下文而言,对象 Customer
的属性(在此例中)将使用默认转换转换为数据库列。在大多数情况下,默认转换不满足应用程序的要求。为了解决这种情况,EF 定义了两种技术来定义所需的转换:数据注解(此处未使用)和 Fluent API。数据注解使用模型类中的属性来定义转换。数据注解存在两个问题。首先,它们是有限的,无法指定 Fluent API 中可用的转换。其次,它们违反了对象或域模型类与数据访问之间的关注点分离原则。Fluent API 使用 DbContext
类中的 OnModelCreating
方法来执行转换。可以在此方法中使用 lambda 表达式定义转换。但是,我们也可以为模型实体定义转换类,并在 OnModelCreating
方法中引用这些类,如下所示。
创建 ~\Data\CustomerConfiguration.cs
初始 Data\CustomerConfiguration.cs
[注意:命名空间是 QuantumWeb.Data
。(见下文。)]
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using QuantumWeb.Model;
namespace QuantumWeb.Data
{
public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
{
public void Configure(EntityTypeBuilder<Customer> builder)
{
builder.ToTable("Customers");
builder.HasKey(c => c.CustomerId);
builder.Property(c => c.CustomerId)
.HasColumnType("int");
builder.Property(c => c.CustomerName)
.IsRequired()
.HasColumnType("nvarchar(50)")
.HasMaxLength(50);
builder.Property(c => c.CustomerContact)
.IsRequired()
.HasColumnType("nvarchar(50)")
.HasMaxLength(50);
builder.Property(c => c.CustomerPhone)
.IsRequired()
.HasColumnType("nvarchar(15)")
.HasMaxLength(15);
builder.Property(c => c.CustomerEmail)
.IsRequired()
.HasColumnType("nvarchar(50)")
.HasMaxLength(50);
} // end public void Configure(EntityTypeBuilder<Customer> builder)
} // end public class CustomerConfiguration : IEntityTypeConfiguration<Customer>
} // end namespace QuantumWeb.Data
下面的表格展示了 Customer
类与数据库之间的映射:
项目 | 名称 | C# 类型 | DB 类型 | 是否必需 | 注释 |
表 | Customers | ||||
CustomerId | int | int | 是 | 主键 | |
CustomerName | 字符串 | nvarchar(50) | 是 | ||
CustomerContact | 字符串 | nvarchar(50) | 是 | ||
CustomerPhone | 字符串 | nvarchar(15) | 是 | ||
CustomerEmail | 字符串 | nvarchar(50) | 是 | |
第一次更新 Data\QuantumDbContext.cs
[注意:命名空间是 QuantumWeb.Data
。(见下文。)]
using Microsoft.EntityFrameworkCore;
using QuantumWeb.Model;
namespace QuantumWeb.Data
{
public class QuantumDbContext : DbContext
{
public QuantumDbContext (DbContextOptions<QuantumDbContext> options)
: base(options)
{
} // end public QuantumDbContext (DbContextOptions<QuantumDbContext> options)
#region DbSets
public DbSet<Customer> Customer { get; set; }
#endregion // DbSets
/// <summary>
/// Data Model Creation Method
/// </summary>
/// <param name="modelBuilder">ModelBuilder instance</param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new CustomerConfiguration());
} // end protected override void OnModelCreating(ModelBuilder modelBuilder)
} // end public class QuantumDbContext : DbContext
} // end namespace QuantumWeb.Data
modelBuilder.ApplyConfiguration()
调用将 CustomerConfiguration
的一个实例注入到数据转换逻辑中。
生成的 Pages\Customers\Index.cshtml
@page
@model QuantumWeb.Pages.Customers.IndexModel
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-page="Create">Create New</a>
<!-- A link to the Pages/Customers/Create page to create a new Customer -->
</p>
<!-- An HTML table to display existing Customers -->
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Customer[0].CustomerName)
</th>
<th>
@Html.DisplayNameFor(model => model.Customer[0].CustomerContact)
</th>
<th>
@Html.DisplayNameFor(model => model.Customer[0].CustomerPhone)
</th>
<th>
@Html.DisplayNameFor(model => model.Customer[0].CustomerEmail)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Customer) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.CustomerName)
</td>
<td>
@Html.DisplayFor(modelItem => item.CustomerContact)
</td>
<td>
@Html.DisplayFor(modelItem => item.CustomerPhone)
</td>
<td>
@Html.DisplayFor(modelItem => item.CustomerEmail)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.CustomerId">Edit</a> |
<!-- A link to the Pages/Customers/Edit page to edit an existing Customer -->
<a asp-page="./Details" asp-route-id="@item.CustomerId">Details</a> |
<!-- A link to the Pages/Customers/Details page to display
the details for an existing Customer -->
<a asp-page="./Delete" asp-route-id="@item.CustomerId">Delete</a>
<!-- A link to the Pages/Customers/Delete page to delete an existing Customer -->
</td>
</tr>
}
</tbody>
</table>
_Pages/Customers/Index.cshtml_ 页面列出了现有的 Customers
,并提供了创建新 Customer
以及编辑、显示详细信息和删除数据库中 Customer
记录的链接。
生成的 Pages\Customers\Index.cshtml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
// No reference to QuantumWeb.Data namespace. Error!!!
using QuantumWeb.Model;
using QuantumWeb.Models; // Error!!!
namespace QuantumWeb.Pages.Customers
{
public class IndexModel : PageModel
{
private readonly QuantumWeb.Models.QuantumDbContext _context; // Error!!!
public CreateModel(QuantumWeb.Models.QuantumDbContext context) // Error!!!
{
_context = context;
}
public IList<Customer> Customer { get; set; }
public async Task OnGetAsync()
{
Customer = await _context.Customer.ToListAsync();
}
}
}
这是 _Customers/Index_ 页面的处理程序。注意标记有“// Error!!
”注释的行。这反映了在脚手架过程之后提到的问题。
- 请注意,使用
QuantumWeb.Models
的行。此命名空间不存在。模型的正确命名空间是QuantumWeb.Model
。此行应从所有已生成的 _cshtml.cs_ 文件中删除。 -
QuantumDbContext
类从QuantumWeb.Models
命名空间引用。该文件位于 _QuantumWeb\Data_ 文件夹中。我们将此命名空间更改为QuantumWeb.Data
。原因是实现关注点分离的最佳实践,将数据访问实体(如QuantumDbContext
)与对象模型实体分开。为了强制执行此概念,我们在所有使用QuantumDbContext
的 _cshtml.cs_ 文件中添加了对QuantumWeb.Data
命名空间的引用。请注意上面 _Data\QuantumDbContext.cs_ 和 _Initial Data\CustomerConfiguration.cs_ 中的命名空间。
第一次修改 Pages\Customers\Index.cshtml.cs
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using QuantumWeb.Data;
using QuantumWeb.Model;
namespace QuantumWeb.Pages.Customers
{
public class IndexModel : PageModel
{
private readonly QuantumDbContext _context;
public IndexModel(QuantumDbContext context)
{
_context = context;
} // end public IndexModel(QuantumDbContext context)
public IList<Customer> Customer { get;set; }
public async Task OnGetAsync()
{
Customer = await _context.Customer.ToListAsync();
} // end public async Task OnGetAsync()
} // end public class IndexModel : PageModel
} // end namespace QuantumWeb.Pages.Customers
我们对 _Pages\Customers\ .cshtml.cs_ 文件进行了类似的更改。
EF Migrations & 数据库创建
此时,我们可以处理 EF migrations 并创建我们的演示数据库。首先,我们需要安装一个 NuGet 包,Microsoft.EntityFrameworkCore.Tools v.2.1.4
。此包允许我们在 Package Manager Console 中使用某些命令。通常,Package Manager Console 显示在 VS2017 IDE 的 Output Window 中作为一个选项卡。
VS2017 IDE 中的 Package Manager Console
如果 Package Manager Console 不可见,您可以使用 Tools > NuGet Package Manager > Package Manager Console 菜单命令打开它。
在 VS2017 IDE 中打开 Package Manager Console
此处进行的许多操作都使用了 Package Manager Console。您可以在 此处探索有关 Package Manager Console 的详细信息。
有两种方法可以安装 NuGet 包。一种是在 Package Console Manager 中使用命令。
[注意:在一个包含多个项目的解决方案中,请确保 Package Manager Console 中引用了正确的项目。]
Install-Package Microsoft.EntityFrameworkCore.Tools -Version 2.1.4
另一种方法是通过 Solution Explorer 完成。
在 VS2017 IDE 中安装 NuGet 包 Microsoft.EntityFrameworkCore v.2.1.4
点击“Install”以安装包。
现在我们可以创建初始 migration。这将把 QuantumDbContext
和 CustomerConfiguration
类中的代码转换为 Migration,以处理应用程序和连接的数据库之间的数据传输。
Add-Migration Initial-Migration
此命令从 Package Manager Console 执行。这将修改解决方案资源管理器,如下所示。
Initial-Migration 后的解决方案资源管理器
生成的 20181019171417_Initial-Migration.cs
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
namespace QuantumWeb.Migrations
{
public partial class InitialMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Customers",
columns: table => new
{
CustomerId = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy",
SqlServerValueGenerationStrategy.IdentityColumn),
CustomerName = table.Column<string>(type: "nvarchar(50)",
maxLength: 50, nullable: false),
CustomerContact = table.Column<string>(type: "nvarchar(50)",
maxLength: 50, nullable: false),
CustomerPhone = table.Column<string>(type: "nvarchar(15)",
maxLength: 15, nullable: false),
CustomerEmail = table.Column<string>(type: "nvarchar(50)",
maxLength: 50, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Customers", x => x.CustomerId);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Customers");
}
}
}
Migrations
类定义了两个方法:Up
,用于处理从应用程序到数据库的转换;Down
,用于撤销这些更改。在进行下一步之前,最好检查 migration 的生成代码。
Update-Database
同样,Update-Database
命令在 Package Manager Console 中执行。
如果这些命令成功,更改将传播到数据库。如果这是对数据库的第一次 migration,并且数据库不存在,则会创建数据库。这假设您拥有数据库服务器的创建数据库权限。现在我们可以通过 VS2017 Server Explorer 连接到数据库。
在 VS2017 Server Explorer 中创建数据库连接
只需右键单击“Data Connections”节点,然后选择“Add Selection...”。
指定服务器和选择数据库
完成此操作后,您可以单击“test”按钮来确认数据库存在并且可以从 VS2017 连接到它。
测试和创建连接
点击“OK”按钮以创建连接。一旦连接建立,您就可以在 Server Explorer 中单击其节点将其打开。然后,展开“Tables”节点,右键单击 Customers 表并选择“Open Table Definition”。然后您应该在数据库中看到如下所示的表定义。
QuantumDbContext 数据库中的 Customers 表定义
此时,我们可以构建并运行应用程序进行调试。
QuantumWeb 应用程序主页:https//: 44306/
点击“Customers”链接以查看 Customers
页面。
QuantumWeb 应用程序 Customers 页面:https//: 44306/Customers
没有 Customer
记录,所以我们的下一个任务是完成 Customer
UI。
摘要
至此,我们已初步创建了一个 ASP.NET Core Razor Page 应用程序 QuantumWeb
,该应用程序显示一个 Customers
的 Index 页面。我们通过 QuantumDbContext
类完成了初步的数据访问功能,并在 localdb
实例中创建了应用程序数据库。
关注点
在本系列的第二部分中,我们将完成 Customer
的 CRUD 功能。