目录
添加项目和项目技能处理
介绍
这是一篇由多部分组成的文章的第四部分,演示了通过EntityFramework Core 2.1(EF)将C#enum值映射到数据库表中的string值。它解决了enum与应用程序实体的一对多和多对多关系中的值映射问题。它在ASP.NET Core Razor Page应用程序的上下文中执行此操作。
EF是对象关系映射器(ORM)。在诸如此示例的应用程序中,有两个“世界”。一个是在C#中作为对象模型存在的对象世界。另一个是存在于关系数据库中的关系世界,如Microsoft SQL Server。这两个世界并不一致。ORM的功能,如EntityFramework,就是这两个世界之间的桥梁,并促进它们之间的数据传输。
第一部分。 设置实体框架数据上下文和初始客户Razor页面。(https://blog.youkuaiyun.com/mzl87/article/details/85269084)
第二部分。 为客户提供完整的CRUD功能。(https://blog.youkuaiyun.com/mzl87/article/details/85312335)
第三部分。创建Project和ProjectState实体,并在ProjectState和Projects之间实现一对多关系(https://blog.youkuaiyun.com/mzl87/article/details/85312583)
在第四部分:添加Skill 实体(Skill 枚举,SkillTitle 和ProjectSkill)并实现Projects 和Skills之间的多对多关系,如下所示:
- 添加实体Skill,SkillTitle和ProjectSkill并配置到QuantumDbContext中。
- 添加迁移,添加项目技能实体和更新数据库。
- 搭建Skill相关的Razor页面,CustomerProjectSkills.cshtml,CustomerProjectSkillAssign.cshtml和CustomerProjectSkillDelete.cshtml。运行测试以确认功能。
背景
本系列中实施的示例应用程序适用于虚拟工程技术公司,量子工程技术公司。这家公司主要服务于石油,天然气和化学工业。到目前为止,我们已经讨论了对象模型的基础,并创建了许多ASP.NET Razor页面来处理客户,项目和项目状态。在最后一部分中,我们将讨论执行工作所需技能的列表。这项工作围绕Skill枚举和Skill与Projects之间的多对多关系构建。可能有许多项目需要某种技能。执行Project还需要很多Skill。因此,项目和技能实体之间存在多对多关系。
在关系数据库中,通过为两个实体创建连接表来实现多对多关系,如下所示。
通过连接表实现多对多关系
表A和表B之间存在多对多关系。在关系数据库中,创建连接表JOIN-TABLE AB,与两个表具有一对多关系。
在先前版本的实体框架(EF)中,可以按约定配置连接表,而无需在对象模型中使用实体或类。但是,截至目前为止,Entity Framework Core尚未提供此功能。(参见 https://www.learnentityframeworkcore.com/configuration/many-to-many-relationship-configuration。)因此,我们需要在对象模型中创建和配置一个类来实现这一目的。以下讨论显示了如何使用相关的Razor页面来管理UI中的内容。
使用代码
工作对象模型显示在第一部分中,并在此处针对 Skills重复。
Skills的工作对象模型
Skill.cs
namespace QuantumWeb.Model
{
/// <summary>
/// Skill Enumeration
/// </summary>
public enum Skill
{
Programmer, // Programmer
ME, // Mechanical Engineer
ChE, // Chemical Engineer
CtrlE, // Control Engineer
SWE, // Software Engineer
SWArch, // Software Architect
WebDes, // Web Designer
DataSci, // Data Scientist
ProjMgr, // Project Manager
BusAnal, // Business Analyst
QA // Quality Assurance Tester
} // end public enum Skill
} // end namespace QuantumWeb.Model
我们提供了一个SkillTitle类,因此我们可以在UI中为枚举值提供相关的标题。
SkillTitle.cs
using System.Collections.Generic;
namespace QuantumWeb.Model
{
/// <summary>
/// SkillTitle Class
/// </summary>
public class SkillTitle
{
/// <summary>
/// Skill Code
/// </summary>
public Skill SkillCode { get; set; }
/// <summary>
/// Skill Title
/// </summary>
public string Title { get; set; }
#region Navigation Properties
/// <summary>
/// List of ProjectSkill Instances
/// </summary>
public List<ProjectSkill> ProjectSkills { get; set; }
#endregion // Navigation Properties
} // end public class SkillTitle
} // end namespace QuantumWeb.Model
此类引用类ProjectSkill,它将在数据库中配置连接的表。
ProjectSkill.cs
namespace QuantumWeb.Model
{
/// <summary>
/// ProjectSkill Class, a join entity
/// </summary>
/// <remarks>
/// Note: The database table will have a non-unique index on ProjectId and SkillCode
/// </remarks>
public class ProjectSkill
{
/// <summary>
/// ProjectSkill Identifier, primary key
/// </summary>
public int ProjectSkillId { get; set; }
#region Navigation Properties
/// <summary>
/// Project Identifier
/// </summary>
public int ProjectId { get; set; }
/// <summary>
/// Project Reference
/// </summary>
public Project Project { get; set; }
/// <summary>
/// Skill Code
/// </summary>
public Skill SkillCode { get; set; }
/// <summary>
/// SkillTitle Reference
/// </summary>
public SkillTitle SkillTitle { get; set; }
#endregion // Navigation Properties
} // end public class ProjectSkill
} // end namespace QuantumWeb.Model
注意导航属性。它是对单个Project实例和单个SkillTitle实例的引用。ProjectId和SkillCode属性将映射到数据库中ProjectSkills表中的外键。另请注意,SkillTitle类具有集合属性ProjectSkills(List <ProjectSkill>),表明它可以与零个或多个ProjectSkill实例相关。我们现在必须修改Project类。
修改Project.cs
using System.Collections.Generic;
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; }
/// <summary>
/// List of ProjectSkill Instances
/// </summary>
public List<ProjectSkill> ProjectSkills { get; set; }
#endregion // Navigation Properties
} // end public class Project
} // end namespace QuantumApp.Model
这里我们添加了一个导航属性ProjectSkills (List <ProjectSkill>),它允许Project与多个ProjectSkill实例相关联。
现在我们必须在QuantumDbContext类中配置这些类以创建数据库映射。 首先,我们创建SkillTitleConfiguration类。
SkillTitleConfiguration.cs
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using QuantumWeb.Model;
namespace QuantumWeb.Data
{
public class SkillTitleConfiguration : IEntityTypeConfiguration<SkillTitle>
{
public void Configure(EntityTypeBuilder<SkillTitle> builder)
{
builder.ToTable("SkillTitles");
builder.HasKey(st => st.SkillCode);
builder.Property(st => st.SkillCode)
.HasColumnType("nvarchar(20)")
.HasConversion(
st => st.ToString(),
st => (Skill)Enum.Parse(typeof(Skill), st));
builder.Property(st => st.Title)
.IsRequired()
.HasColumnType("nvarchar(50)")
.HasMaxLength(50);
} // end public void Configure(EntityTypeBuilder<SkillTitle> builder)
} // end public class SkillTitleConfiguration : IEntityTypeConfiguration<SkillTitle>
} // end namespace QuantumWeb.Data
这会将SkillTitle类映射到SkillTitles数据库表。它还可以在SkillTitles表中配置Skill枚举值和SkillCode字符串列值之间的转换。这类似于将ProjectState枚举值映射到第III部分中讨论的ProjectStateCode值。
我们现在可以配置ProjectSkill类到连接表ProjectSkills的映射。
ProjectSkillConfiguration.cs
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using QuantumWeb.Model;
namespace QuantumWeb.Data
{
public class ProjectSkillConfiguration : IEntityTypeConfiguration<ProjectSkill>
{
public void Configure(EntityTypeBuilder<ProjectSkill> builder)
{
builder.ToTable("ProjectSkills");
builder.HasKey(ps => ps.ProjectSkillId);
builder.Property(ps => ps.ProjectSkillId)
.HasColumnType("int");
builder.Property(ps => ps.ProjectId)
.HasColumnType("int");
builder.Property(ps => ps.SkillCode)
.HasColumnType("nvarchar(20)")
.HasConversion(
ps => ps.ToString(),
ps => (Skill)Enum.Parse(typeof(Skill), ps));
builder.HasIndex(ps => new { ps.ProjectId, ps.SkillCode })
.IsUnique(false);
builder.HasOne<Project>(ps => ps.Project)
.WithMany(p => p.ProjectSkills)
.HasForeignKey(ps => ps.ProjectId);
builder.HasOne<SkillTitle>(ps => ps.SkillTitle)
.WithMany(p => p.ProjectSkills)
.HasForeignKey(ps => ps.SkillCode);
} // end public void Configure(EntityTypeBuilder<ProjectSkill> builder)
} // end public class ProjectSkillConfiguration : IEntityTypeConfiguration<ProjectSkill>
} // 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; }
/// <summary>
/// SkillTitle DbSet
/// </summary>
public DbSet<SkillTitle> SkillTitles { get; set; }
/// <summary>
/// ProjectSkill DbSet
/// </summary>
public DbSet<ProjectSkill> ProjectSkills { 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());
modelBuilder.ApplyConfiguration(new SkillTitleConfiguration());
modelBuilder.ApplyConfiguration(new ProjectSkillConfiguration());
} // end protected override void OnModelCreating(ModelBuilder modelBuilder)
} // end public class QuantumDbContext : DbContext
} // end namespace QuantumWeb.Data
这里我们定义DbSets,SkillTitles和ProjectSkills,并添加SkillTitleConfiguration和ProjectSkillConfiguration类以便在OnModelCreating方法中进行处理。现在,我们在Package Manager控制台中创建迁移并更新数据库。
Add-Migration Add-Project-Skill-Entities
生成20181025222456_Add-Project-Skill-Entities.cs
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
namespace QuantumWeb.Migrations
{
public partial class AddProjectSkillEntities : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "SkillTitles",
columns: table => new
{
SkillCode = table.Column<string>(type: "nvarchar(20)", nullable: false),
Title = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SkillTitles", x => x.SkillCode);
});
migrationBuilder.CreateTable(
name: "ProjectSkills",
columns: table => new
{
ProjectSkillId = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy",
SqlServerValueGenerationStrategy.IdentityColumn),
ProjectId = table.Column<int>(type: "int", nullable: false),
SkillCode = table.Column<string>(type: "nvarchar(20)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProjectSkills", x => x.ProjectSkillId);
table.ForeignKey(
name: "FK_ProjectSkills_Projects_ProjectId",
column: x => x.ProjectId,
principalTable: "Projects",
principalColumn: "ProjectId",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProjectSkills_SkillTitles_SkillCode",
column: x => x.SkillCode,
principalTable: "SkillTitles",
principalColumn: "SkillCode",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ProjectSkills_SkillCode",
table: "ProjectSkills",
column: "SkillCode");
migrationBuilder.CreateIndex(
name: "IX_ProjectSkills_ProjectId_SkillCode",
table: "ProjectSkills",
columns: new[] { "ProjectId", "SkillCode" });
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ProjectSkills");
migrationBuilder.DropTable(
name: "SkillTitles");
}
}
}
有一些关键点需要考虑。
- SkillTitles表有一个主键SkillCode,它映射到Skill枚举中的值。
- ProjectSkills表有一个整数主键ProjectSkillId和两个外键ProjecId,用于链接到Project记录,SkillCode用于链接到SkillTitle记录。一些作者建议设置一个多值主键,ProjectId和SkillCode。这将为需要多种相同类型技能的项目设置一些问题。但是,我们设置了一个非唯一索引IX_ProjectSkills_ProjectId_SkillCode。
我们稍后会看到其中的一些功能。现在将迁移到数据库。
Update-Database
从SQL Server Management Studio(SSMS)生成的下图显示了相关的数据库表。
客户——项目——技能数据库图
现在我们在UI中包含这些实体。首先,我们在CustomerProjects Index页面中创建ProjectSkills的链接。
修改后的CustomerProject.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="./CustomerProjectSkills" asp-route-id="@item.ProjectId">
ProjectSkills
</a> |
<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>
CustomerProjectSkills的链接要求我们构建一个新的Razor页面。
构建Customers/CustomerProjectSkills Razor页面
初始化~Pages\Customers\CustomerProjectSkills.cshtml
@page "{id:int?}"
@model QuantumWeb.Pages.Customers.CustomerProjectSkillsModel
@{
ViewData["Title"] = "Customer Project Skills";
}
<h2>Customer Project Skills</h2>
<p>
<a asp-page="./CustomerProjects" asp-route-id="@Model.Customer.CustomerId">Back to List</a> |
<a asp-page="CustomerProjectSkillAssign" asp-route-id="@Model.Project.ProjectId">Assign Skill</a>
</p>
<div>
<h4>Customer-Project</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.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.ProjectSkills)
</dt>
<dd>
<table class="table">
<tr>
<th>Project Skill Id</th>
<th>Skill Code</th>
<th>Skill Title</th>
<th></th>
</tr>
@foreach (var item in Model.Project.ProjectSkills)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.ProjectSkillId)
</td>
<td>
@Html.DisplayFor(modelItem => item.SkillCode)
</td>
<td>
@Html.DisplayFor(modelItem => item.SkillTitle.Title)
</td>
<td>
<a asp-page="./CustomerProjectSkillDelete"
asp-route-id="@item.ProjectSkillId">
Delete
</a>
</td>
</tr>
}
</table>
</dd>
</dl>
</div>
这会将页面配置为使用可为空的参数id,这将允许将目标Project的ProjectId传递给OnGet处理程序。有一个指向CustomerProjectSkillAssign页面的链接,该页面将创建一个ProjectSkill记录,有效地为项目分配技能。还有另一个指向CustomerProjectSkillDelete页面的链接,该页面将删除ProjectSkill记录。我们稍后会显示这两页的代码。
初始化~Pages\Customers\CustomerProjectSkills.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 CustomerProjectSkillsModel : PageModel
{
private readonly QuantumDbContext _context;
public CustomerProjectSkillsModel(QuantumDbContext context)
{
_context = context;
} // end public CustomerProjectSkillsModel(QuantumDbContext context)
public Project Project { get; set; }
public Customer Customer { 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)
.Include(p => p.ProjectSkills)
.ThenInclude(ps => ps.SkillTitle)
.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)
} // end public class CustomerProjectSkillsModel : PageModel
} // end namespace QuantumWeb.Pages.Customers
请注意实体框架(EF)预加载的示例。
Project = await _context.Projects
.Include(p => p.Customer)
.Include(p => p.ProjectSkills)
.ThenInclude(ps => ps.SkillTitle)
.FirstOrDefaultAsync(p => p.ProjectId == id);
在EF中,使用include()和include扩展方法在单个查询中检索与预加载相关的实体。在这里,我们检索项目的相关Customer和ProjectSkills实体,其ProjectId具有输入参数id的值。该查询更进一步使用ThenInclude()方法检索与检索到的ProjectSkills相关联的SkillTitles。
接下来的几个屏幕截图显示了导航到此页面的顺序。
QuantumWeb应用程序主页:https//localhost:44306/
QuantumWeb应用程序客户索引页:https//localhost: 44306/Customers
客户项目页面包含Mirarex Oil & Gas(已添加ProjectSkills链接)的2个项目
Mirarex Oil&Gas,Zolar Pipeline的客户项目技能页面(无技能)
我们现在展示CustomerProjectSkillAssign Razor页面的构建。
构建Customers/CustomerProjectSkillAssign Razor页面
初始化~Pages\Customers\CustomerProjectSkillAssign.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 CustomerProjectSkillAssignModel : PageModel
{
private readonly QuantumDbContext _context;
public CustomerProjectSkillAssignModel(QuantumDbContext context)
{
_context = context;
} // end public CustomerProjectSkillAssignModel(QuantumDbContext context)
[BindProperty]
public Project Project { get; set; }
[BindProperty]
public Customer Customer { get; set; }
[BindProperty]
public SkillTitle SkillTitle { 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)
.Include(p => p.ProjectSkills)
.ThenInclude(ps => ps.SkillTitle)
.FirstOrDefaultAsync(p => p.ProjectId == id);
if (Project == null)
{
return NotFound();
} // endif (Project == null)
Customer = Project.Customer;
ViewData["SkillCode"] = new SelectList(_context.SkillTitles, "SkillCode", "Title");
return Page();
}// end public async Task<IActionResult> OnGet(int? id)
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
} // endif (!ModelState.IsValid)
ProjectSkill projectSkill = new ProjectSkill()
{
ProjectId = Project.ProjectId,
SkillCode = SkillTitle.SkillCode
};
_context.ProjectSkills.Add(projectSkill);
await _context.SaveChangesAsync();
return RedirectToPage("./CustomerProjectSkills", new { id = Project.ProjectId });
} // end public async Task<IActionResult> OnPostAsync()
} // end public class CustomerProjectSkillAssignModel : PageModel
} // end namespace QuantumWeb.Pages.Customers
在这里,我们再次使用ViewData来设置选择列表,如第III部分所述。(译者注:此处和上一篇中枚举映射下拉框一样,需要手动在数据库表SkillTitles中添加对应的Skill枚举值和标题描述信息)
ViewData["SkillCode"] = new SelectList(_context.SkillTitles, "SkillCode", "Title");
这次它处理SkillTitles以选择与项目关联的技能。
初始化~Pages\Customers\CustomerProjectSkillAssign.cshtml
@page "{id:int?}"
@model QuantumWeb.Pages.Customers.CustomerProjectSkillAssignModel
@{
ViewData["Title"] = "Customer Project Skill Assignment";
}
<h2>Customer Project Skill Assignment</h2>
<hr />
<dl class="dl-horizontal">
<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.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="Project.ProjectId" />
<div class="form-group">
<label asp-for="SkillTitle.SkillCode" class="control-label"></label>
<select asp-for="SkillTitle.SkillCode" class="form-control" asp-items="ViewBag.SkillCode"></select>
</div>
<div class="form-group">
<a asp-page="./CustomerProjectSkills" asp-route-id="Project.ProjectId">Project Skills</a> |
<input type="submit" value="Assign" class="btn btn-default" />
</div>
</form>
</div>
</div>
Zolar Pipeline的客户项目技能分配页面(技能选择打开)
Zolar Pipeline的客户项目技能分配页面(分配一个程序员)
Mirarex Oil&Gas,Zolar Pipeline的客户项目技能页面(程序员分配)
分配了几个技能之后,这个页面看起来像:
Mirarex Oil & Gas, Zolar Pipeline 的客户项目技能页面(几项技能)
管理层决定分配的程序员太多,因此我们需要删除一个。我们现在将构建CustomerProjectSkillDelete页面。
构建Customers/CustomerProjectSkillDelete Razor Page
初始化~Pages\Customers\CustomerProjectSkillDelete.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 CustomerProjectSkillDeleteModel : PageModel
{
private readonly QuantumDbContext _context;
public CustomerProjectSkillDeleteModel(QuantumDbContext context)
{
_context = context;
} // end public CustomerProjectSkillDeleteModel(QuantumDbContext 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("./CustomerProjectSkills", new { id = Project.Customer.CustomerId });
} // end public async Task<IActionResult> OnPostAsync(int? id)
} // end public class CustomerProjectSkillDeleteModel : PageModel
} // end namespace QuantumWeb.Pages.Customers
初始化~Pages\Customers\CustomerProjectSkillDelete.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, Zolar Pipeline的客户项目技术删除页面
Mirarex Oil&Gas,Zolar Pipeline的客户项目技能页面(已删除记录)
原文地址:https://www.codeproject.com/Articles/1264741/ASP-NET-Core-Razor-Pages-Using-EntityFramework-C-3