目录
添加项目和项目状态处理
介绍
这是一篇由多部分组成的文章的第三部分,演示了通过EntityFramework Core 2.1(EF)将C#enum值映射到数据库表中的string值。它解决了enum与应用程序实体的一对多和多对多关系中的值映射问题。它在ASP.NET Core Razor Page应用程序的上下文中执行此操作。
EF是对象关系映射器(ORM)。在诸如此示例的应用程序中,有两个“世界”。一个是在C#中作为对象模型存在的对象世界。另一个是存在于关系数据库中的关系世界,如Microsoft SQL Server。这两个世界并不一致。ORM的功能,如EntityFramework,就是这两个世界之间的桥梁,并促进它们之间的数据传输。
第一部分。设置实体框架数据上下文和初始Customer的Razor页面
第二部分。完成了Customers的CRUD功能
在第三部分。我们将创建Project和ProjectState实体并在ProjectState和Project之间实现一个一对多的关系,如下:
- 添加Project,ProjectState和ProjectStateDescription实体。
- 添加EF迁移以在数据库中创建和配置Projects和ProjectStateDescriptions表。
- 演示enum对象模型实体中的string值与Projects和ProjectStateDescriptions数据库表中的值之间的转换。
- 搭建,实现和测试包含ProjectState功能的ProjectCRUD页面,如CustomerProjects.cshtml,CustomerProjectCreate.cshtml,CustomerProjectDetails.cshtml和CustomerProjectDelete.cshtml Razor页面。
使用代码
添加初始项目处理。
接下来,我们启用Customer项目处理。该应用程序使用Customer作为“网关”实体; 一切都是通过Customer。Customer和Projects之间存在一对多的关系。因此,我们需要修改Customer类。
修改后的Customer.cs:
-
using System.Collections.Generic;
-
-
namespace QuantumWeb.Model
-
{
-
/// <summary>
-
/// Customer Class
-
/// </summary>
-
public class Customer
-
{
-
-
-
/// <summary>
-
/// Parameter-less Constructor
-
/// </summary>
-
/// <remarks>
-
/// Required for scaffolding the UI
-
/// </remarks>
-
public Customer()
-
{
-
} // end public Customer()
-
-
-
-
/// <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; }
-
-
-
-
/// <summary>
-
/// List of Projects
-
/// </summary>
-
public List<Project> Projects { get; set; }
-
-
-
-
} // end public class Customer
-
-
} // end namespace QuantumWeb.Model
我们添加了一个项目列表。在这里,我们将某些属性标识为导航属性。这些属性引用其他类/实体,以便我们可以在处理中导航到它们。Customer在Projects列表中表示零或多个Projects。初始Project类定义如下。
初始Project.cs:
-
namespace QuantumWeb.Model
-
{
-
/// <summary>
-
/// Project Class
-
/// </summary>
-
public class Project
-
{
-
/// <summary>
-
/// Project Identifier, primary key
-
/// </summary>
-
public int ProjectId { get; set; }
-
/// <summary>
-
/// Project Name
-
/// </summary>
-
public string ProjectName { get; set; }
-
-
-
-
/// <summary>
-
/// Customer Identifier
-
/// </summary>
-
public int CustomerId { get; set; }
-
-
/// <summary>
-
/// Customer
-
/// </summary>
-
/// <remarks>
-
/// Every Project has a Customer
-
/// </remarks>
-
public Customer Customer { get; set; }
-
-
/// <summary>
-
/// Project Status Code
-
/// </summary>
-
public ProjectState ProjectStateCode { get; set; }
-
-
/// <summary>
-
/// ProjectStateDescription Reference
-
/// </summary>
-
public ProjectStateDescription ProjectStateDescription { get; set; }
-
-
-
-
} // end public class Project
-
-
} // end namespace QuantumApp.Model
除了定义初始化Project类之外,我们还将在Model文件夹中定义ProjectState enum。
ProjectState.cs:
-
namespace QuantumWeb.Model
-
{
-
/// <summary>
-
/// Project State Enumeration
-
/// </summary>
-
public enum ProjectState
-
{
-
Prospect,
-
UnderReview,
-
StartScheduled,
-
InProgress,
-
Completed
-
} // end public enum ProjectState
-
-
} // end namespace QuantumWeb.Model
这个enum指定了Project工作流的状态。
- Prospect。这涉及一个有前景的Project。这个Project可能是通过推荐或其他营销工作提出的。尚未进行任何研究,且规格尚不清楚。
- UnderReview。在这种状态下,Project制定了要求,初始预算和进度表。没有承诺Quantum或者Customer。
- StartScheduled。已经指定了工作开始的日期,并且正在准备开始工作。
- InProgress。实际工作已经开始但尚未完成。
- Completed。项目工作完成。
如前所述,我们对此应用程序有两个目标。
- 我们应该为Project将在UI中显示的每个状态定义简短描述,以帮助用户理解每个状态的含义。
- 每个enum值都作为string类型存储在数据库中。
为了满足ProjectState enum的这些要求,我们定义了ProjectStateDescription类。
ProjectStateDescription.cs:
-
using System.Collections.Generic;
-
-
namespace QuantumWeb.Model
-
{
-
/// <summary>
-
/// Project State Description Class
-
/// </summary>
-
public class ProjectStateDescription
-
{
-
/// <summary>
-
/// ProjectState Code
-
/// </summary>
-
public ProjectState ProjectStateCode { get; set; }
-
-
/// <summary>
-
/// State Description
-
/// </summary>
-
public string StateDescription { get; set; }
-
-
-
-
/// <summary>
-
/// Projects Collection
-
/// </summary>
-
public List<Project> Projects { get; set; }
-
-
-
-
} // end public class ProjectStateDescription
-
-
} // end namespace QuantumWeb.Model
ProjectState对Projects的一对多的关系,通过导航属性启用。每个Project都有一个ProjectStateDesciption。每个ProjectStateDescripton都有一个Projects集合。
接下来,我们需要为Project和ProjectStateDescription定义EF配置类,并在QuantumDbContext类中包含所有内容。所有此活动都发生在Data文件夹中。
初始ProjectConfiguration.cs:
-
using System;
-
using Microsoft.EntityFrameworkCore;
-
using Microsoft.EntityFrameworkCore.Metadata.Builders;
-
using QuantumWeb.Model;
-
-
namespace QuantumWeb.Data
-
{
-
public class ProjectConfiguration : IEntityTypeConfiguration<Project>
-
{
-
public void Configure(EntityTypeBuilder<Project> builder)
-
{
-
builder.ToTable("Projects");
-
builder.HasKey(p => p.ProjectId);
-
builder.Property(p => p.ProjectId)
-
.HasColumnType("int");
-
builder.Property(p => p.ProjectName)
-
.IsRequired()
-
.HasColumnType("nvarchar(80)")
-
.HasMaxLength(80);
-
builder.Property(p => p.CustomerId)
-
.HasColumnType("int")
-
.IsRequired();
-
builder.HasOne(p => p.Customer)
-
.WithMany(c => c.Projects)
-
.HasForeignKey(p => p.CustomerId)
-
.IsRequired();
-
builder.Property(p => p.ProjectStateCode)
-
.HasColumnType("nvarchar(15)")
-
.HasDefaultValue(ProjectState.Prospect)
-
.HasConversion(
-
p => p.ToString(),
-
p => (ProjectState)Enum.Parse(typeof(ProjectState), p));
-
builder.HasOne(p => p.ProjectStateDescription)
-
.WithMany(pd => pd.Projects)
-
.HasForeignKey(p => p.ProjectStateCode);
-
} // end public void Configure(EntityTypeBuilder<Project> builder)
-
-
} // end public class ProjectConfiguration : IEntityTypeConfiguration<Project>
-
-
} // end namespace QuantumWeb.Data
看看下面提取的行:
-
builder.HasOne(p => p.Customer)
-
.WithMany(c => c.Projects)
-
.HasForeignKey(p => p.CustomerId)
-
.IsRequired();
对这些行的解释是,“每个Project都有一个带有许多Projects的Customer。每个Project都映射到Projects数据库中的表,通过外键CustomerId,并且这是必需的。因此,Customer- Project关系是一对多。
在一对多ProjectStateDescription- Project关系被配置为:
-
builder.HasOne(p => p.ProjectStateDescription)
-
.WithMany(pd => pd.Projects)
-
.HasForeignKey(p => p.ProjectStateCode);
接下来,我们将了解处理enum的值到数据库string列配置的方式。
-
builder.Property(p => p.ProjectStateCode)
-
.HasColumnType("nvarchar(15)")
-
.HasDefaultValue(ProjectState.Prospect)
-
.HasConversion(
-
p => p.ToString(),
-
p => (ProjectState)Enum.Parse(typeof(ProjectState), p));
这些行首先在Projects名为的表中配置一个列ProjectStateCode,类型为nvarchar(15),其默认值来自ProjectState.Prospect。接下来,定义ProjectState值和string值之间的转换。当将值从ProjectState enum移动到Projects表时,将使用该ToString()函数转换值。换另一种方式时,表中string的值将被解析为一个enum值。始终使用相同的方案在数据库列中的enum值和string值之间进行转换。
ProjectStateDescriptionConfiguration类如下所示。
ProjectStateDescriptionConfiguration.cs:
-
using System;
-
using Microsoft.EntityFrameworkCore;
-
using Microsoft.EntityFrameworkCore.Metadata.Builders;
-
using QuantumWeb.Model;
-
-
namespace QuantumWeb.Data
-
{
-
/// <summary>
-
/// ProjectState Description Configuration Class
-
/// </summary>
-
public class ProjectStateDescriptionConfiguration :
-
IEntityTypeConfiguration<ProjectStateDescription>
-
{
-
-
public void Configure(EntityTypeBuilder<ProjectStateDescription> builder)
-
{
-
builder.ToTable("ProjectStateDescriptions");
-
builder.HasKey(p => p.ProjectStateCode);
-
builder.Property(p => p.ProjectStateCode)
-
.HasColumnType("nvarchar(15)")
-
.HasConversion(
-
p => p.ToString(),
-
p => (ProjectState)Enum.Parse(typeof(ProjectState), p));
-
builder.Property(p => p.StateDescription)
-
.IsRequired()
-
.HasColumnType("nvarchar(80)")
-
.HasMaxLength(80);
-
} // end public void Configure(EntityTypeBuilder<ProjectStateDescription> builder)
-
-
} // end public class ProjectStateDescriptionConfiguration :
-
// IEntityTypeConfiguration<ProjectStateDescription>
-
-
} // end namespace QuantumWeb.Data
现在,我们更新QuantumDbContext类。
然后更新QuantumDbContext.cs:
-
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)
-
-
-
-
/// <summary>
-
/// Customer DbSet
-
/// </summary>
-
public DbSet<Customer> Customers { get; set; }
-
-
/// <summary>
-
/// Project DbSet
-
/// </summary>
-
public DbSet<Project> Projects { get; set; }
-
-
/// <summary>
-
/// ProjectStateDescription DbSet
-
/// </summary>
-
public DbSet<ProjectStateDescription> ProjectStateDescriptions { get; set; }
-
-
-
-
/// <summary>
-
/// Data Model Creation Method
-
/// </summary>
-
/// <param name="modelBuilder">ModelBuilder instance</param>
-
protected override void OnModelCreating(ModelBuilder modelBuilder)
-
{
-
modelBuilder.ApplyConfiguration(new CustomerConfiguration());
-
modelBuilder.ApplyConfiguration(new ProjectConfiguration());
-
modelBuilder.ApplyConfiguration(new ProjectStateDescriptionConfiguration());
-
} // end protected override void OnModelCreating(ModelBuilder modelBuilder)
-
-
} // end public class QuantumDbContext : DbContext
-
-
} // end namespace QuantumWeb.Data
现在为Project和ProjectState实体添加EF迁移。(译者注:同样需要调整appsettings.json中数据库连接字符串,建议删除Migrations文件夹后在执行下面的命令,同时提醒,在执行下面命令后需要命令update-database更新到数据库)
Add-Migration Added-Project-ProjectState
生成 ~Migrations20181021203503_Added-Project-ProjectState.cs:
-
using Microsoft.EntityFrameworkCore.Metadata;
-
using Microsoft.EntityFrameworkCore.Migrations;
-
-
namespace QuantumWeb.Migrations
-
{
-
public partial class AddedProjectProjectState : Migration
-
{
-
protected override void Up(MigrationBuilder migrationBuilder)
-
{
-
migrationBuilder.CreateTable(
-
name: "ProjectStateDescriptions",
-
columns: table => new
-
{
-
ProjectStateCode =
-
table.Column<string>(type: "nvarchar(15)", nullable: false),
-
StateDescription =
-
table.Column<string>(type: "nvarchar(80)", maxLength: 80, nullable: false)
-
},
-
constraints: table =>
-
{
-
table.PrimaryKey("PK_ProjectStateDescriptions", x => x.ProjectStateCode);
-
});
-
-
migrationBuilder.CreateTable(
-
name: "Projects",
-
columns: table => new
-
{
-
ProjectId = table.Column<int>(type: "int", nullable: false)
-
.Annotation("SqlServer:ValueGenerationStrategy",
-
SqlServerValueGenerationStrategy.IdentityColumn),
-
ProjectName = table.Column<string>(type: "nvarchar(80)",
-
maxLength: 80, nullable: false),
-
CustomerId = table.Column<int>(type: "int", nullable: false),
-
ProjectStateCode = table.Column<string>
-
(type: "nvarchar(15)", nullable: false, defaultValue: "Prospect")
-
},
-
constraints: table =>
-
{
-
table.PrimaryKey("PK_Projects", x => x.ProjectId);
-
table.ForeignKey(
-
name: "FK_Projects_Customers_CustomerId",
-
column: x => x.CustomerId,
-
principalTable: "Customers",
-
principalColumn: "CustomerId",
-
onDelete: ReferentialAction.Cascade);
-
table.ForeignKey(
-
name: "FK_Projects_ProjectStateDescriptions_ProjectStateCode",
-
column: x => x.ProjectStateCode,
-
principalTable: "ProjectStateDescriptions",
-
principalColumn: "ProjectStateCode",
-
onDelete: ReferentialAction.Cascade);
-
});
-
-
migrationBuilder.CreateIndex(
-
name: "IX_Projects_CustomerId",
-
table: "Projects",
-
column: "CustomerId");
-
-
migrationBuilder.CreateIndex(
-
name: "IX_Projects_ProjectStateCode",
-
table: "Projects",
-
column: "ProjectStateCode");
-
}
-
-
protected override void Down(MigrationBuilder migrationBuilder)
-
{
-
migrationBuilder.DropTable(
-
name: "Projects");
-
-
migrationBuilder.DropTable(
-
name: "ProjectStateDescriptions");
-
}
-
}
-
}
在Update- Database命令之后,SQL Server Management Studio(SSMS)中的数据库关系图如下所示。
使用Customer- Project- ProjectState表的QuantumDbContext数据库关系图:
修改Project和ProjectState的Razor 页。
我们需要为项目的应用程序添加一些自定义客户Razor 页面。首先,我们需要为CustomerProjects添加一个指向Customer/Index页面的链接。
添加CustomerProjects 链接指向PagesCustomersIndex.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="./CustomerProjects" asp-route-id="@item.CustomerId">Projects</a> |
-
<!--
-
A link to the Pages/Customers/CustomerProjects page to display & manage the
-
Projects 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>
我们将如下构建几个自定义Customers Razor页面。
为客户设计的定制构建Razor页面:
搭建Customers/CustomerProjects Razor 页面:
单击“ 添加 ”将为CustomerProjects Index页面生成shell文件。
生成~PagesCustomersCustomerProjects.cshtml
-
@page
-
@model QuantumWeb.Pages.Customers.CustomerProjectsModel
-
@{
-
ViewData["Title"] = "CustomerProjects";
-
}
-
-
<h2>CustomerProjects</h2>
生成~PagesCustomersCustomerProjects.cshtml.cs
-
using System;
-
using System.Collections.Generic;
-
using System.Linq;
-
using System.Threading.Tasks;
-
using Microsoft.AspNetCore.Mvc;
-
using Microsoft.AspNetCore.Mvc.RazorPages;
-
-
namespace QuantumWeb.Pages.Customers
-
{
-
public class CustomerProjectsModel : PageModel
-
{
-
public void OnGet()
-
{
-
-
}
-
}
-
}
我们将在每种情况下修改这些shell文件以满足我们的需求。CustomerProjects Index 页面的修改文件。
修改了~PagesCustomersCustomerProjects.cshtml
-
@page "{id:int?}"
-
@model QuantumWeb.Pages.Customers.CustomerProjectsModel
-
@{
-
ViewData["Title"] = "Customer Projects";
-
}
-
-
<h2>Customer Projects</h2>
-
-
<div>
-
<h4>Customer</h4>
-
<hr />
-
<dl class="dl-horizontal">
-
<dt>
-
@Html.DisplayNameFor(model => model.Customer.CustomerId)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Customer.CustomerId)
-
</dd>
-
<dt>
-
@Html.DisplayNameFor(model => model.Customer.CustomerName)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Customer.CustomerName)
-
</dd>
-
<dt>
-
@Html.DisplayNameFor(model => model.Customer.Projects)
-
</dt>
-
<dd>
-
<table class="table">
-
<tr>
-
<th>Project ID</th>
-
<th>Project Name</th>
-
<th>Project State</th>
-
<th></th>
-
</tr>
-
@foreach (var item in Model.Customer.Projects)
-
{
-
<tr>
-
<td>
-
@Html.DisplayFor(modelItem => item.ProjectId)
-
</td>
-
<td>
-
@Html.DisplayFor(modelItem => item.ProjectName)
-
</td>
-
<td>
-
@Html.DisplayFor(modelItem => item.ProjectStateCode)
-
</td>
-
<td>
-
<a asp-page="./CustomerProjectEdit"
-
-
asp-route-id="@item.ProjectId">Edit</a> |
-
<a asp-page="./CustomerProjectDelete"
-
-
asp-route-id="@item.ProjectId">Delete</a>
-
</td>
-
</tr>
-
}
-
</table>
-
</dd>
-
</dl>
-
</div>
-
-
<div>
-
<a asp-page="CustomerProjectCreate" asp-route-id="@Model.Customer.CustomerId">
-
Create New Project</a> |
-
<a asp-page="./Index">Back to List</a>
-
</div>
“ {id:int?}”表示需要整数参数,id需要或者请求页面将返回HTTP 401(未找到页面)错误。在这种情况下,这是目标Customer的标识符(CustomerId)。另外,请注意引用该CustomerProjectCreate页面的链接。
<a asp-page="CustomerProjectCreate" asp-route-id="@Model.Customer.CustomerId">Create New Project</a> |
这将把我们带到CustomerProjectCreate尚未创建的页面,为引用Customer创建一个新的Project。
修改了~PagesCustomersCustomerProjects.cshtml.cs
-
using System.Threading.Tasks;
-
using Microsoft.AspNetCore.Mvc;
-
using Microsoft.AspNetCore.Mvc.RazorPages;
-
using Microsoft.EntityFrameworkCore;
-
using QuantumWeb.Data;
-
using QuantumWeb.Model;
-
-
namespace QuantumWeb.Pages.Customers
-
{
-
public class CustomerProjectsModel : PageModel
-
{
-
private readonly QuantumDbContext _context;
-
-
public CustomerProjectsModel(QuantumDbContext context)
-
{
-
_context = context;
-
} // end public CustomerProjectsModel(QuantumDbContext context)
-
-
public Customer Customer { get; set; }
-
-
public async Task<IActionResult> OnGet(int? id)
-
{
-
if (id == null)
-
{
-
return NotFound();
-
} // endif (id == null)
-
-
Customer = await _context.Customers
-
.Include(c => c.Projects)
-
.FirstOrDefaultAsync(c => c.CustomerId == id);
-
-
if (Customer == null)
-
{
-
return NotFound();
-
} // endif (Customer == null)
-
-
return Page();
-
} // end public async Task<IActionResult> OnGet(int? id)
-
-
} // end public class CustomerProjectsModel : PageModel
-
-
} // end namespace QuantumWeb.Pages.Customers
请注意,OnGet处理程序具有可为空的整数参数,id应该是如上所述的CustomerId。
QuantumWeb 应用客户页面: https//localhost: 44306/Customers 具有项目链接。
Customer Projects页面:https//localhost: 44306/Customers/CustomerProjects/1(无项目)
“ 创建新项目 ”链接将激活自定义CustomerProjectCreate Razor页面。我们现在搭建这个页面。
搭建Customers/CustomerProjectCreate Razor页面:
Initial~PagesCustomersCustomerProjectCreate.cshtml.cs
-
using System.Threading.Tasks;
-
using Microsoft.AspNetCore.Mvc;
-
using Microsoft.AspNetCore.Mvc.RazorPages;
-
using Microsoft.AspNetCore.Mvc.Rendering;
-
using Microsoft.EntityFrameworkCore;
-
using QuantumWeb.Data;
-
using QuantumWeb.Model;
-
-
namespace QuantumWeb.Pages.Customers
-
{
-
public class CustomerProjectCreateModel : PageModel
-
{
-
private readonly QuantumDbContext _context;
-
-
public CustomerProjectCreateModel(QuantumDbContext context)
-
{
-
_context = context;
-
} // end public CustomerProjectCreateModel(QuantumContext context)
-
-
[
-
public Customer Customer { get; set; }
-
-
public async Task<IActionResult> OnGet(int? id)
-
{
-
if (id == null)
-
{
-
return NotFound();
-
} // endif (id == null)
-
-
Customer = await _context.Customers
-
.Include(c => c.Projects)
-
.FirstOrDefaultAsync(c => c.CustomerId == id);
-
-
if (Customer == null)
-
{
-
return NotFound();
-
} // endif (Customer == null)
-
-
ViewData["ProjectStateCode"] = new SelectList(_context.ProjectStateDescriptions,
-
"ProjectStateCode", "StateDescription", ProjectState.Prospect);
-
-
return Page();
-
-
} // end public async Task<IActionResult> OnGet(int? id)
-
-
[
-
public Project Project { get; set; }
-
-
public async Task<IActionResult> OnPostAsync()
-
{
-
if (!ModelState.IsValid)
-
{
-
return Page();
-
} // endif (!ModelState.IsValid)
-
-
Project.CustomerId = Customer.CustomerId;
-
-
_context.Projects.Add(Project);
-
await _context.SaveChangesAsync();
-
-
return RedirectToPage("./CustomerProjects", new { id = Customer.CustomerId });
-
} // end public async Task<IActionResult> OnPostAsync()
-
-
} // end public class CustomerProjectCreateModel : PageModel
-
-
} // end namespace QuantumWeb.Pages.Customers
请注意此代码中的这些行。
-
[
-
public Customer Customer { get; set; }
该[BindProperty]将Customer实例绑定到UI的元素,以便在浏览器和Web服务器之间保留它们的值。另请注意,此属性也适用于Project实例。
-
Customer = await _context.Customers
-
.Include(c => c.Projects)
-
.FirstOrDefaultAsync(c => c.CustomerId == id);
此语句对数据库执行查询,以检索Customer其主键值CustomerId与输入参数id值及其关联Project记录匹配的记录。如果有,该.Include函数的功能是查询中包含相关记录。
-
ViewData["ProjectStateCode"] = new SelectList(_context.ProjectStateDescriptions,
-
"ProjectStateCode", "StateDescription", ProjectState.Prospect);
ViewData是一个无类型的键值字典,用于在CustomerProjectCreateModel类(在.cshtml.cs文件中)和.cshtml文件中的HTML 之间传递值。这类似于MVC中将数据从Controller 传递到View,在使用ViewData中,数据仅在HTTP请求中持久存在。其成员由ProjectStateDescriptions数据库表中的查询填充。在这种情况下,_context.ProjectStateDescriptions是IEnumerable<ProjectStateDescription>从查询返回的。ProjectStateCode是表中的主键,表示ViewData字典中的键。StateDescription成为ViewData字典中的关联值。ViewData将用来填充在CustomerProjectCreate.cshtml(见下文)中的<select>元素。ProjectState.Prospect是为<select>从ProjectState enum中默认选择的值。您可以阅读更多ViewData信息在以下链接上 https://www.tektutorialshub.com/viewbag-viewdata-asp-net-core/。(译者注:需要在ProjectStateDescriptions数据库表中手动加入数据,具体可见下图展示的数据加,ProjectStateCode字段的值就是对应枚举中的值--定义在代码中的名称。如此值为Completed,StateDescription字段值为project is complete,以此类推)
初始化~Pages CustomersCustomerProjectCreate.cshtml:
-
@page
-
@model QuantumWeb.Pages.Customers.CustomerProjectCreateModel
-
@{
-
ViewData["Title"] = "Create Customer Project";
-
}
-
-
<h2>Create Customer Project</h2>
-
<hr />
-
<dl class="dl-horizontal">
-
<dt>
-
@Html.DisplayNameFor(model => model.Customer.CustomerId)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Customer.CustomerId)
-
</dd>
-
<dt>
-
@Html.DisplayNameFor(model => model.Customer.CustomerName)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Customer.CustomerName)
-
</dd>
-
</dl>
-
<div class="row">
-
<div class="col-md-4">
-
<form method="post">
-
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
-
<input type="hidden" asp-for="Customer.CustomerId" />
-
<div class="form-group">
-
<label asp-for="Project.ProjectName" class="control-label"></label>
-
<input asp-for="Project.ProjectName" class="form-control">
-
</div>
-
<div class="form-group">
-
<label asp-for="Project.ProjectStateCode" class="control-label"></label>
-
<select asp-for="Project.ProjectStateCode" class="form-control"
-
-
asp-items="ViewBag.ProjectStateCode">
-
</select>
-
</div>
-
<div class="form-group">
-
<input type="submit" value="Create" class="btn btn-default" />
-
</div>
-
</form>
-
</div>
-
</div>
-
-
<div>
-
<a asp-page="CustomerProjects" asp-route-id="@Model.Customer.CustomerId">
-
Back to Customer Projects
-
</a>
-
</div>
-
-
@section Scripts {
-
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
-
}
关键要素如下:
<input type="hidden" asp-for="Customer.CustomerId" />
这个隐藏<input>捕获目标CustomerId以便在<form>发布时可用它来创建Project。
-
<select asp-for="Project.ProjectStateCode" class="form-control"
-
asp-items="ViewBag.ProjectStateCode">
-
</select>
此<select>元素将显示为UI中的下拉列表,其中包含CustomerProjectCreate.OnGet()方法中ViewData填充的值。
初始化 ~PagesCustomersCustomerProjectCreate.cshtml:
这将显示最初显示的Customers/CustomerProjectCreate页面。
CustomerProjectCreate 包含数据的页面:
点击“ Create”后,我们会看到:
客户Projects页面添加Project:
接下来的两个图显示了为两个Customers添加其他Projects之后的情况。
客户项目页面包含Mirarex Oil&Gas的2个项目:
客户项目页面包含Polyolefin Processing, Inc.的3个项目
我们现在可以添加另一个页面来编辑Customer项目,CustomerProjectEdit页面。
搭建 Customers/CustomerProjectEdit Razor Page
初始化~PagesCustomersCustomerProjectEdit.cshtml.cs
-
using System.Threading.Tasks;
-
using Microsoft.AspNetCore.Mvc;
-
using Microsoft.AspNetCore.Mvc.RazorPages;
-
using Microsoft.AspNetCore.Mvc.Rendering;
-
using Microsoft.EntityFrameworkCore;
-
using QuantumWeb.Data;
-
using QuantumWeb.Model;
-
-
namespace QuantumApp.Pages.Customers
-
{
-
public class CustomerProjectEditModel : PageModel
-
{
-
private readonly QuantumDbContext _context;
-
-
public CustomerProjectEditModel(QuantumDbContext context)
-
{
-
_context = context;
-
} // end public CustomerProjectEditModel(QuantumDbContext context)
-
-
[
-
public Customer Customer { get; set; }
-
[
-
public Project Project { get; set; }
-
-
public async Task<IActionResult> OnGet(int? id)
-
{
-
if (id == null)
-
{
-
return NotFound();
-
} // endif (id == null)
-
-
Project = await _context.Projects
-
.Include(p => p.Customer)
-
.FirstOrDefaultAsync(p => p.ProjectId == id);
-
-
if (Project == null)
-
{
-
return NotFound();
-
} // endif (Project == null)
-
-
Customer = Project.Customer;
-
-
ViewData["ProjectStateCode"] = new SelectList(_context.ProjectStateDescriptions,
-
"ProjectStateCode", "StateDescription", ProjectState.Prospect);
-
-
return Page();
-
} // end public async Task<IActionResult> OnGet(int? id)
-
-
public async Task<IActionResult> OnPostAsync(int? id)
-
{
-
if (!ModelState.IsValid)
-
{
-
return Page();
-
} // endif (!ModelState.IsValid)
-
-
var projectToUpdate = await _context.Projects.FindAsync(id);
-
-
if (projectToUpdate == null)
-
{
-
return NotFound();
-
} // endif (projectToUpdate == null)
-
-
projectToUpdate.CustomerId = Customer.CustomerId;
-
-
if (await TryUpdateModelAsync<Project>(
-
projectToUpdate,
-
"project",
-
p => p.ProjectName, p => p.ProjectStateCode))
-
{
-
await _context.SaveChangesAsync();
-
return RedirectToPage("./CustomerProjects", new { id = Customer.CustomerId });
-
}
-
-
return Page();
-
} // end public async Task<IActionResult> OnPostAsync(int? id)
-
-
} // end public class CustomerProjectEditModel : PageModel
-
-
} // end namespace QuantumApp.Pages.Customers
此代码与CustomerProjectCreate页面在.Include和ViewData方面具有相同的构件。
初始化~PagesCustomersCustomerProjectEdit.cshtml
-
@page "{id:int?}"
-
@model QuantumWeb.Pages.Customers.CustomerProjectEditModel
-
@{
-
ViewData["Title"] = "Edit Customer Project";
-
}
-
-
<h2>Edit Customer Project</h2>
-
<hr />
-
<dl class="dl-horizontal">
-
<dt>
-
@Html.DisplayNameFor(model => model.Customer.CustomerId)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Customer.CustomerId)
-
</dd>
-
<dt>
-
@Html.DisplayNameFor(model => model.Customer.CustomerName)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Customer.CustomerName)
-
</dd>
-
</dl>
-
<div class="row">
-
<div class="col-md-4">
-
<form method="post">
-
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
-
<input type="hidden" asp-for="Customer.CustomerId" />
-
<div class="form-group">
-
<label asp-for="Project.ProjectName" class="control-label"></label>
-
<input asp-for="Project.ProjectName" class="form-control">
-
</div>
-
<div class="form-group">
-
<label asp-for="Project.ProjectStateCode" class="control-label"></label>
-
<select asp-for="Project.ProjectStateCode" class="form-control"
-
-
asp-items="ViewBag.ProjectStateCode">
-
</select>
-
</div>
-
<div class="form-group">
-
<input type="submit" value="Save" class="btn btn-default" />
-
</div>
-
</form>
-
</div>
-
</div>
-
-
<div>
-
<a asp-page="CustomerProjects" asp-route-id="@Model.Customer.CustomerId">
-
Back to Customer Projects
-
</a>
-
</div>
-
-
@section Scripts {
-
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
-
}
关于CustomerId的隐藏<input>和<select>,此页面具有与CustomerProjectCreate页面相同的元素。
Customer Projects 页面包含Mirarex Oil&Gas的2个项目——用于编辑:
Mirarex Oil&Gas, Zolar Pipeline的客户项目编辑页面:
客户项目页面包含Mirarex Oil & Gas 的2个项目——项目编辑:
通过CustomerProjectDelete页面,此项目的最后一个功能是删除。
搭建 Customers/CustomerProjectDelete Razor页面:
初始化~PagesCustomersCustomerProjectDelete.cshtml.cs
-
using System.Threading.Tasks;
-
using Microsoft.AspNetCore.Mvc;
-
using Microsoft.AspNetCore.Mvc.RazorPages;
-
using Microsoft.EntityFrameworkCore;
-
using QuantumWeb.Data;
-
using QuantumWeb.Model;
-
-
namespace QuantumWeb.Pages.Customers
-
{
-
public class CustomerProjectDeleteModel : PageModel
-
{
-
private readonly QuantumDbContext _context;
-
-
public CustomerProjectDeleteModel(QuantumDbContext context)
-
{
-
_context = context;
-
} // end public CustomerProjectDeleteModel(QuantumContext context)
-
-
[
-
public Customer Customer { get; set; }
-
[
-
public Project Project { get; set; }
-
-
public async Task<IActionResult> OnGetAsync(int? id)
-
{
-
if (id == null)
-
{
-
return NotFound();
-
} // endif (id == null)
-
-
Project = await _context.Projects
-
.Include(p => p.Customer)
-
.FirstOrDefaultAsync(p => p.ProjectId == id);
-
-
if (Project == null)
-
{
-
return NotFound();
-
} // endif (Project == null)
-
-
Customer = Project.Customer;
-
-
return Page();
-
} // end public async Task<IActionResult> OnGet(int? id)
-
-
public async Task<IActionResult> OnPostAsync(int? id)
-
{
-
if (id == null)
-
{
-
return NotFound();
-
} // endif (id == null)
-
-
Project = await _context.Projects
-
.Include(p => p.Customer)
-
.FirstOrDefaultAsync(p => p.ProjectId == id);
-
-
if (Project != null)
-
{
-
_context.Projects.Remove(Project);
-
await _context.SaveChangesAsync();
-
} // endif (Project != null)
-
-
return RedirectToPage("./CustomerProjects", new { id = Project.Customer.CustomerId });
-
} // end public async Task<IActionResult> OnPostAsync(int? id)
-
-
} // end public class CustomerProjectDeleteModel : PageModel
-
-
} // end namespace QuantumWeb.Pages.Customer
初始化~PagesCustomersCustomerProjectDelete.cshtml
-
@page "{id:int?}"
-
@model QuantumWeb.Pages.Customers.CustomerProjectDeleteModel
-
@{
-
ViewData["Title"] = "Delete Customer Project";
-
}
-
-
<h2>Delete Customer Project</h2>
-
-
<h3>Are you sure you want to delete this?</h3>
-
<div>
-
<dl class="dl-horizontal">
-
<dt>
-
@Html.DisplayNameFor(model => model.Customer.CustomerName)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Customer.CustomerName)
-
</dd>
-
<dt>
-
@Html.DisplayNameFor(model => model.Project.ProjectId)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Project.ProjectId)
-
</dd>
-
<dt>
-
@Html.DisplayNameFor(model => model.Project.ProjectName)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Project.ProjectName)
-
</dd>
-
<dt>
-
@Html.DisplayNameFor(model => model.Project.ProjectStateCode)
-
</dt>
-
<dd>
-
@Html.DisplayFor(model => model.Project.ProjectStateCode)
-
</dd>
-
</dl>
-
-
<form method="post">
-
<input type="hidden" asp-for="Project.ProjectId" />
-
<a asp-page="CustomerProjects" asp-route-id="@Model.Customer.CustomerId">
-
Back to Customer Projects
-
</a> |
-
<input type="submit" value="Delete" class="btn btn-default" />
-
</form>
-
</div>
客户项目页面包含Mirarex Oil & Gas的3个项目:
删除客户项目页面——删除Ouachita Shale:
客户项目页面包含Mirarex Oil&Gas的2个项目:
此时,我们可以总结下表中的测试数据:
Customers, Projects, ProjectStates
CustomerId |
Customer Name |
ProjectId |
Project Name |
ProjectStateCode |
StateDescription |
1 |
Mirarex Oil & Gas, LLC |
1 |
Zolar Pipeline |
UnderReview |
Project is under review and negotiation |
1 |
Mirarex Oil & Gas, LLC |
2 |
Nelar Ranch Gas Fracturing |
Prospect |
Prospective or referred project |
2 |
Polyolefin Processing, Inc. |
3 |
Port Gibson Plant Expansion |
Prospect |
Prospective or referred project |
2 |
Polyolefin Processing, Inc. |
4 |
Jackson Plant Control System Upgrade |
Prospect |
Prospective or referred project |
2 |
Polyolefin Processing, Inc. |
5 |
Eutaw Plant Shutdown & Maintenance |
Prospect |
Prospective or referred project |
下面可以进入第四部分进行学习。
https://blog.csdn.net/mzl87/article/details/85312583
原文地址:https://www.codeproject.com/Articles/1264330/ASP-NET-Core-Razor-Pages-Using-EntityFramework-C-2