.Net Core Razor 页面,具有同一实体的多个下拉列表

.Net Core Razor page with multiple drop-down's for the same entity

有什么方法可以让多个下拉菜单在同一个 razor 页面上显示来自同一个数据库实体的数据,而无需创建多个具有新 ID(例如 ResourceID;ResourceID1;ResourceID2)的 classes

我能够在 'Create.cshtml' 和 'Edit.cshtml' razor 页面中使用来自 MS SQL 数据库的适当数据显示下拉列表,但是保存时选择的数据显示所选资源的 ID,而不是 'Index.cshtml'、'Detail.cshtml' 和 'Delete.cshtml' 视图中的资源名称。

资源模型:

namespace ProjectReporting.Models
{
    public class Resource
    {
        public int ID { get; set; }

        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        [Display(Name = "Long Name")]
        public string LongName { get; set; }

        [DefaultValue(true)]
        [Display(Name = "Active")]
        public bool IsActive { get; set; } = true;

        [Display(Name = "Is Manager")]
        public bool IsManager { get; set; }

        [Display(Name = "Is Forecast Owner")]
        public bool IsForecastOwner { get; set; }

        public ICollection<Project> Projects { get; set; }

    }
}

项目模型:

namespace ProjectReporting.Models
{
    public class Project
    {
        public int ID { get; set; }

        [Display(Name = "ID")]
        public int PID { get; set; }

        [Display(Name = "Project Name")]
        public string ProjectName { get; set; }

        [Display(Name = "Forecast Owner")]
        public int ResourceID { get; set; }
        public Resource Resource { get; set; }

        [Display(Name = "DSM")]
        public int? ResourceID1 { get; set; }

        public ICollection<ProjectComment> ProjectComments { get; set; }

    }
}

Create.cshtml 页面:

@page
@model ProjectReporting.Pages.Projects.CreateModel

@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>

<h4>Project</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Project.PID" class="control-label"></label>
                <input asp-for="Project.PID" class="form-control" />
                <span asp-validation-for="Project.PID" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Project.ProjectName" class="control-label"></label>
                <input asp-for="Project.ProjectName" class="form-control" />
                <span asp-validation-for="Project.ProjectName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Project.ResourceID" class="control-label"></label>
                <select asp-for="Project.ResourceID" class="form-control" asp-items="ViewBag.ResourceID"><option value="" default="" selected="">-- Select --</option></select>
            </div>
            <div class="form-group">
                <label asp-for="Project.ResourceID1" class="control-label"></label>
                <select asp-for="Project.ResourceID1" class="form-control" asp-items="ViewBag.ResourceID1"><option value="" default="" selected="">-- Select --</option></select>
            </div>
            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="Project.IsArchived" /> @Html.DisplayNameFor(model => model.Project.IsArchived)
                </label>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Create.cshtml 页面:

namespace ProjectReporting.Pages.Projects
{
    public class CreateModel : PageModel
    {
        private readonly ProjectReporting.Data.ApplicationDbContext _context;

        public CreateModel(ProjectReporting.Data.ApplicationDbContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
            ViewData["OrganisationID"] = new             SelectList(_context.ProjectType.Where(a => a.IsActive == true), "ID", "TypeName");
            ViewData["ResourceID"] = new SelectList(_context.Resource.Where(a => a.IsActive & a.IsForecastOwner == true), "ID", "LongName");
            ViewData["ResourceID1"] = new SelectList(_context.Resource.Where(a => a.IsActive == true), "ID", "LongName");
            return Page();
        }

        [BindProperty]
        public Project Project { get; set; }

        // To protect from overposting attacks, please enable the specific properties you want to bind to, for
        // more details see https://aka.ms/RazorPagesCRUD.
        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Project.Add(Project);
            await _context.SaveChangesAsync();

            return RedirectToPage("./Index");
        }
    }
}

Index.cshtml 页面:

@page
@model ProjectReporting.Pages.Projects.IndexModel

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Project[0].PID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Project[0].Organisation)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Project[0].ProjectName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Project[0].Resource)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Project[0].ResourceID1)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Project[0].IsArchived)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Project) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.PID)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Organisation.OrgName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ProjectName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Resource.LongName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => c)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.IsArchived)
            </td>
            <td>
                <a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
                <a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

item.Resource.LongName 对于第一个资源工作正常,但我希望 item.Resource.LongName 也能如此。

Index.cshtml.cs

namespace ProjectReporting.Pages.Projects
{
    public class IndexModel : PageModel
    {
        private readonly ProjectReporting.Data.ApplicationDbContext _context;

        public IndexModel(ProjectReporting.Data.ApplicationDbContext context)
        {
            _context = context;
        }

        public IList<Project> Project { get;set; }

        public async Task OnGetAsync()
        {
            Project = await _context.Project
                .Include(p => p.Resource).ToListAsync();
        }
    }
}

我已经在迁移文件中设置了 FK 以创建能够检索数据的数据库,并且希望避免必须按资源创建一个 class 文件。

table.ForeignKey(
     name: "FK_Project_Resource_ResourceID",
     column: x => x.ResourceID,
     principalTable: "Resource",
     principalColumn: "ID",
     onDelete: ReferentialAction.Restrict);
table.ForeignKey(
     name: "FK_Project_Resource_ResourceID1",
     column: x => x.ResourceID1,
     principalTable: "Resource",
     principalColumn: "ID",
     onDelete: ReferentialAction.Restrict);

结果在下拉列表中显示了正确的数据,并且在保存时选择了正确的资源 ID。但是索引、详情、删除页面只显示ResourceID,不显示LongName。如果我对第二个 ResourceID1 使用 Resource.LongName,它会正确显示与 ResourceID 相同的 LongName。

如何让页面上的多个资源下拉列表指向同一实体并在索引、详细信息和删除页面上显示 LongName?

不清楚你在 ResourceProject 之间的关系,你不能同时使用 ResourceIDResourceID1 作为 Resource 属性用于恢复不同的资源。

多对多关系,可以参考

https://docs.microsoft.com/en-us/ef/core/modeling/relationships#many-to-many

一种解决方法是您只需在处理程序中获取所有资源并在视图中检索它:

Index.cshtml.cs:

public class IndexModel : PageModel
{
    private readonly ProjectReporting.Data.ApplicationDbContext _context;

    public IndexModel(ProjectReporting.Data.ApplicationDbContext context)
    {
        _context = context;
    }

    public IList<Project> Project { get;set; }
    public IList<Resource> Resources { get; set; }

    public async Task OnGetAsync()
    {
        Resources = await _context.Resource.ToListAsync();
        Project = await _context.Projects
            .Include(p => p.Resource).ToListAsync();
    }
}

Index.cshtml:

<td>
    @Html.DisplayFor(modelItem => item.Resource.LongName)
</td>
<td>
    @{ 
        var resource = Model.Resources.FirstOrDefault(r => r.ID == item.ResourceID1);
    }
    @resource.LongName
</td>