使用EntityFramework Core和Enums作為字串的ASP.NET Core Razor頁面——第三部分
目錄
新增專案和專案狀態處理
介紹
這是一篇由多部分組成的文章的第三部分,演示了通過EntityFramework Core 2.1(EF)將C#enum值對映到資料庫表中的string值。它解決了enum與應用程式實體的一對多和多對多關係中的值對映問題。它在ASP.NET Core Razor Page應用程式的上下文中執行此操作。
EF是物件關係對映器(ORM)。在諸如此示例的應用程式中,有兩個“世界”。一個是在C#中作為物件模型存在的物件世界。另一個是存在於關係資料庫中的關係世界,如Microsoft SQL Server
第一部分。設定實體框架資料上下文和初始Customer的Razor頁面
第二部分。完成了Customers的CRUD功能
在第三部分。我們將建立Project和ProjectState實體並在ProjectState和Project之間實現一個一對多的關係,如下:
- 新增Project,ProjectState和ProjectStateDescription實體。
- 新增EF遷移以在資料庫中建立和配置Projects和ProjectStateDescription
- 演示enum物件模型實體中的string值與Projects和ProjectStateDescriptions資料庫表中的值之間的轉換。
- 搭建,實現和測試包含ProjectState功能的ProjectCRUD頁面,如CustomerProjects.cshtml,CustomerProjectCreate.cshtml,CustomerProjectDetails.cshtml和CustomerProjectDelete.cshtml Razor頁面。
使用程式碼
新增初始專案處理。
接下來,我們啟用Customer專案處理。該應用程式使用Customer
修改後的Customer.cs:
using System.Collections.Generic;
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; }
#region Navigation Properties
/// <summary>
/// List of Projects
/// </summary>
public List<Project> Projects { get; set; }
#endregion // Navigation Properties
} // 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; }
#region Navigation Properties
/// <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; }
#endregion // Navigation Properties
} // 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; }
#region Navigation Properties
/// <summary>
/// Projects Collection
/// </summary>
public List<Project> Projects { get; set; }
#endregion // Navigation Properties
} // 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)
#region DbSets
/// <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; }
#endregion // DbSets
/// <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遷移。
Add-Migration Added-Project-ProjectState
生成 ~\Migrations\20181021203503_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 連結指向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="./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檔案。
生成~Pages\Customers\CustomerProjects.cshtml
@page
@model QuantumWeb.Pages.Customers.CustomerProjectsModel
@{
ViewData["Title"] = "CustomerProjects";
}
<h2>CustomerProjects</h2>
生成~Pages\Customers\CustomerProjects.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 頁面的修改檔案。
修改了~Pages\Customers\CustomerProjects.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。
修改了~Pages\Customers\CustomerProjects.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~Pages\Customers\CustomerProjectCreate.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)
[BindProperty]
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)
[BindProperty]
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
請注意此程式碼中的這些行。
[BindProperty]
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/。
初始化~Pages\ Customers\CustomerProjectCreate.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填充的值。
初始化 ~Pages\Customers\CustomerProjectCreate.cshtml:
這將顯示最初顯示的Customers/CustomerProjectCreate頁面。
CustomerProjectCreate 包含資料的頁面:
點選“ Create”後,我們會看到:
客戶Projects頁面新增Project:
接下來的兩個圖顯示了為兩個Customers新增其他Projects之後的情況。
客戶專案頁面包含Mirarex Oil&Gas的2個專案:
客戶專案頁面包含Polyolefin Processing, Inc.的3個專案
我們現在可以新增另一個頁面來編輯Customer專案,CustomerProjectEdit頁面。
搭建 Customers/CustomerProjectEdit Razor Page
初始化~Pages\Customers\CustomerProjectEdit.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)
[BindProperty]
public Customer Customer { get; set; }
[BindProperty]
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方面具有相同的構件。
初始化~Pages\Customers\CustomerProjectEdit.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頁面:
初始化~Pages\Customers\CustomerProjectDelete.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)
[BindProperty]
public Customer Customer { get; set; }
[BindProperty]
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
初始化~Pages\Customers\CustomerProjectDelete.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://www.codeproject.com/Articles/1264330/ASP-NET-Core-Razor-Pages-Using-EntityFramework-C-2