1. 程式人生 > >使用EntityFramework Core和Enums作為字串的ASP.NET Core Razor頁面——第三部分

使用EntityFramework Core和Enums作為字串的ASP.NET Core Razor頁面——第三部分

目錄

介紹

使用程式碼


新增專案和專案狀態處理

介紹

這是一篇由多部分組成的文章的第三部分,演示了通過EntityFramework Core 2.1EF)將Cenum值對映到資料庫表中的string值。它解決了enum與應用程式實體的一對多和多對多關係中的值對映問題。它在ASP.NET Core Razor Page應用程式的上下文中執行此操作。

EF是物件關係對映器(ORM)。在諸如此示例的應用程式中,有兩個世界。一個是在C#中作為物件模型存在的物件世界。另一個是存在於關係資料庫中的關係世界,如Microsoft SQL Server

。這兩個世界並不一致。ORM的功能,如EntityFramework,就是這兩個世界之間的橋樑,並促進它們之間的資料傳輸。

第一部分。設定實體框架資料上下文和初始CustomerRazor頁面

第二部分。完成了CustomersCRUD功能

在第三部分。我們將建立ProjectProjectState實體並在ProjectStateProject之間實現一個一對多的關係,如下:

  • 新增ProjectProjectStateProjectStateDescription實體。
  • 新增EF遷移以在資料庫中建立和配置ProjectsProjectStateDescription
    s表。
  • 演示enum物件模型實體中的string值與ProjectsProjectStateDescriptions資料庫表中的值之間的轉換。
  • 搭建,實現和測試包含ProjectState功能的ProjectCRUD頁面,如CustomerProjects.cshtmlCustomerProjectCreate.cshtmlCustomerProjectDetails.cshtmlCustomerProjectDelete.cshtml Razor頁面。

使用程式碼

新增初始專案處理。

接下來,我們啟用Customer專案處理。該應用程式使用Customer

作為閘道器實體一切都是通過CustomerCustomerProjects之間存在一對多的關係。因此,我們需要修改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

我們添加了一個專案列表。在這裡,我們將某些屬性標識為導航屬性。這些屬性引用其他類/實體,以便我們可以在處理中導航到它們。CustomerProjects列表中表示零或多個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。專案工作完成。

如前所述,我們對此應用程式有兩個目標。

  1. 我們應該為Project將在UI中顯示的每個狀態定義簡短描述,以幫助使用者理解每個狀態的含義。
  2. 每個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

ProjectStateProjects的一對多的關係,通過導航屬性啟用。每個Project都有一個ProjectStateDesciption每個ProjectStateDescripton都有一個Projects集合。

接下來,我們需要為ProjectProjectStateDescription定義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都有一個帶有許多ProjectsCustomer。每個Project都對映到Projects資料庫中的表,通過外來鍵CustomerId,並且這是必需的。因此,CustomerProject關係是一對多。

在一對多ProjectStateDescriptionProject關係被配置為:

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

現在為ProjectProjectState實體新增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");
        }
    }
}

UpdateDatabase命令之後,SQL Server Management StudioSSMS)中的資料庫關係圖如下所示。

使用CustomerProjectProjectState表的QuantumDbContext資料庫關係圖:

https://img-blog.csdnimg.cn/20181228195522488

修改ProjectProjectStateRazor 頁。

我們需要為專案的應用程式新增一些自定義客戶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頁面:

https://img-blog.csdnimg.cn/20181228195522543

搭建Customers/CustomerProjects Razor 頁面:

https://img-blog.csdnimg.cn/20181228195522598

單擊“ 新增 ”將為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 具有專案連結。

https://img-blog.csdnimg.cn/20181228195522645

Customer Projects頁面:https//localhost: 44306/Customers/CustomerProjects/1(無專案)

https://img-blog.csdnimg.cn/20181227224121669

“ 建立新專案 ”連結將啟用自定義CustomerProjectCreate Razor頁面。我們現在搭建這個頁面。

搭建Customers/CustomerProjectCreate Razor頁面:

https://img-blog.csdnimg.cn/2018122722531162

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

https://img-blog.csdnimg.cn/20181228195522684

這將顯示最初顯示的Customers/CustomerProjectCreate頁面。

CustomerProjectCreate 包含資料的頁面:

https://img-blog.csdnimg.cn/20181228195522740

點選“ Create後,我們會看到:

客戶Projects頁面新增Project

https://img-blog.csdnimg.cn/20181228195522787

接下來的兩個圖顯示了為兩個Customers新增其他Projects之後的情況。

客戶專案頁面包含Mirarex OilGas2個專案:

https://img-blog.csdnimg.cn/20181227224121714

客戶專案頁面包含Polyolefin Processing, Inc.3個專案

https://img-blog.csdnimg.cn/20181228195522829

我們現在可以新增另一個頁面來編輯Customer專案,CustomerProjectEdit頁面。

搭建 Customers/CustomerProjectEdit Razor Page

https://img-blog.csdnimg.cn/20181228195522869

初始化~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頁面在.IncludeViewData方面具有相同的構件。

初始化~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 OilGas2個專案——用於編輯:

https://img-blog.csdnimg.cn/20181227224121750

Mirarex OilGas, Zolar Pipeline的客戶專案編輯頁面:

https://img-blog.csdnimg.cn/20181228195522919

客戶專案頁面包含Mirarex Oil & Gas 2個專案——專案編輯:

https://img-blog.csdnimg.cn/20181227224121795

通過CustomerProjectDelete頁面,此專案的最後一個功能是刪除。

搭建 Customers/CustomerProjectDelete Razor頁面:

https://img-blog.csdnimg.cn/20181227225311112

初始化~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 & Gas3個專案:

https://img-blog.csdnimg.cn/20181227224121848

刪除客戶專案頁面——刪除Ouachita Shale

https://img-blog.csdnimg.cn/20181227225311154

客戶專案頁面包含Mirarex OilGas2個專案:

https://img-blog.csdnimg.cn/20181227224121888

此時,我們可以總結下表中的測試資料:

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