.Net Core - 在“创建子记录”保存后,从父项预填充子记录中的外键导致导航错误

.Net Core -Prepopulating foreign(parent) key in child record from parent results in error in navigation after ‘create child record’ save

您好,我在两个实体之间存在父子关系 - PositionSummary 和 PositionDetail。

这是模型。

    using System;
using System.Collections.Generic;

namespace ThePositionerRazor2.Models
{
    public partial class Possummary
    {
        public Possummary()
        {
            Posdetail = new HashSet<Posdetail>();
        }

        public int PositionId { get; set; }
        public string PositionNbr { get; set; }
        public string WorkTitle { get; set; }
        public string Purpose { get; set; }
        public double? JobValue { get; set; }
        public double? TimeTotal { get; set; }
        public double? Fte { get; set; }
        public double? Salary { get; set; }
        public DateTime? Lastupdated { get; set; }
        public string JobFamily { get; set; }
        public int? DescriptionTypeId { get; set; }

        public virtual Descriptiontype DescriptionType { get; set; }
        public virtual ICollection<Posdetail> Posdetail { get; set; }
    }
}

    using System;
using System.Collections.Generic;

namespace ThePositionerRazor2.Models
{
    public partial class Posdetail
    {
        public int PosdetailId { get; set; }
        public int PositionId { get; set; }
        public int Workitem { get; set; }
        public int? TimeSpent { get; set; }
        public int? ImportanceId { get; set; }
        public double? TimeNrmz { get; set; }
        public int? Knowdepth { get; set; }
        public int? Need { get; set; }
        public int? TimeCalc { get; set; }
        public double? Postskval { get; set; }
        public double? Ftetime { get; set; }
        public double? Ftesal { get; set; }
        public DateTime Lastupdated { get; set; }

        public virtual Imp Importance { get; set; }
        public virtual Knowdep KnowdepthNavigation { get; set; }
        public virtual Possummary Position { get; set; }
        public virtual Timescale TimeSpentNavigation { get; set; }
        public virtual Workhier WorkitemNavigation { get; set; }
    }
}

父级成功导航到选定的子级记录列表。在子列表页面上,我导航到带有参数(父外键)的子创建页面,因为我不想每次都输入父外键。 创建页面 OnPostAsync 过程 returns 到保存后的子列表页面(即标准脚手架代码)。 我的代码编译没有错误。当我点击创建按钮时,创建页面的记录确实将其保存在 SQL 服务器数据库中,但导航回子列表页面会导致错误。

错误是: ArgumentOutOfRangeException:索引超出范围。必须为非负数且小于集合的大小。 (参数'index') ThePositionerRazor2.Pages.PositionDetail.Pages_PositionDetail_Index.ExecuteAsync() 在 Index.cshtml + 14. 新建

这个想法是,在 return 到子列表时 - return 会成功并且如果要求另一个创建 - 父外键默认值仍然有效。

**问题:

  1. 为什么会出现上述错误?
  2. 如何让父外键在重复“创建”条目时在列表和创建页面之间保持有效?
  3. 与 2- 相同的问题,但 return 反复创建带有“返回列表”的页面作为导航出的方式?**

总的来说,我发现在不同的 razor 页面(使用 entity framework 的标准脚手架)上创建子记录还有很多不足之处——当需要创建子记录来预填充父外国时,这非常麻烦关键是一个常见的场景。

想法?

下面是 PositionSummary 和 PositionDetail 的 cshtml 文件和 cs 文件

持仓总结

@page
@model ThePositionerRazor2.Pages.PositionSummary.IndexModel

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

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>

<div class="row">
    <div class="col-md-12">
        <div class="panel panel-primary list-panel" id="list-panel">
            <div class="panel-heading list-panel-heading">
                <h1 class="panel-title list-panel-title">Position Summary</h1>
            </div>
            <div class="panel-body">
                <table id="Possum-data-table"
                       class="table table-striped table-bordered"
                       style="width:100%">
                    @*<table class="table">*@
                    <thead>
                        <tr>
                            <th>
                                @Html.DisplayNameFor(model => model.Possummary[0].PositionNbr)
                            </th>
                            <th>
                                @Html.DisplayNameFor(model => model.Possummary[0].WorkTitle)
                            </th>
                            <th>
                                @Html.DisplayNameFor(model => model.Possummary[0].Purpose)
                            </th>
                            
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        @foreach (var item in Model.Possummary)
                        {
                        <tr>
                            <td>
                                @Html.DisplayFor(modelItem => item.PositionNbr)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.WorkTitle)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Purpose)
                            </td>
                           
                        <td>
                            <a asp-page="./Edit" asp-route-id="@item.PositionId">Edit</a> |
                            @*<a asp-page="./Details" asp-route-id="@item.PositionId">Details</a> |*@
                            <a asp-page="../PositionDetail/Index" asp-route-id="@item.PositionId">Position Details</a> |

                            <a asp-page="./Delete" asp-route-id="@item.PositionId">Delete</a>
                        </td>
                        </tr>
                        }
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
@section Scripts
    {
    <link href="https://cdn.datatables.net/1.10.15/css/dataTables.bootstrap.min.css" rel="stylesheet" />
    <script src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js"></script>
    <script src="https://cdn.datatables.net/1.10.15/js/dataTables.bootstrap4.min.js "></script>

    <script type="text/javascript">
        $(document).ready(function () {

            $('#Possum-data-table').DataTable({ "order": [[0, "asc"]] });

        });
    </script>
}




using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ThePositionerRazor2.Models;

namespace ThePositionerRazor2.Pages.PositionSummary
{
    public class IndexModel : PageModel
    {
        private readonly ThePositionerRazor2.Models.WorkManagerV4Context _context;

        public IndexModel(ThePositionerRazor2.Models.WorkManagerV4Context context)
        {
            _context = context;
        }

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

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

仓位详情索引

@page
@model ThePositionerRazor2.Pages.PositionDetail.IndexModel

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

<h1>Index</h1>



<p>
    <a asp-page="Create">Create New</a>
        <a asp-page="/PositionDetail/Create" asp-route-PositionID="@Model.Posdetail[0].PositionId">Create New</a>

</p>


<form method="post">
    <p>
        Desired Position: @Html.TextBox("SelectedPosition")
    </p>
    <input type="submit" value="Search Positions" />
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-primary list-panel" id="list-panel">
                <div class="panel-heading list-panel-heading">
                    <h1 class="panel-title list-panel-title">Position Detail</h1>
                </div>
                <div class="panel-body">
                    <table id="posdet-data-table"
                           class="table table-striped table-bordered"
                           style="width:100%">
                        @*<table class="table">*@
                        <thead>
                            <tr>
                                <th>
                                    @Html.DisplayNameFor(model => model.Posdetail[0].Position)
                                </th>
                                <th>

                                    @Html.DisplayNameFor(model => model.Posdetail[0].WorkitemNavigation)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.Posdetail[0].TimeNrmz)
                                </th>
                                <th>
                                    @Html.DisplayNameFor(model => model.Posdetail[0].Importance)
                                </th>

                                <th>
                                    @Html.DisplayNameFor(model => model.Posdetail[0].Lastupdated)
                                </th>
                                <th></th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach (var item in Model.Posdetail)
                            {
                                <tr>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.Position.PositionNbr)
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.WorkitemNavigation.Workitemid)
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.TimeNrmz)
                                    </td>
                                    <td>
                                        @Html.DisplayFor(modelItem => item.Importance.ImportanceId)
                                    </td>

                                    <td>
                                        @Html.DisplayFor(modelItem => item.Lastupdated)
                                    </td>

                                    <td>
                                        <a asp-page="./Edit" asp-route-id="@item.PosdetailId">Edit</a> |
                                        <a asp-page="./Details" asp-route-id="@item.PosdetailId">Details</a> |
                                        <a asp-page="./Delete" asp-route-id="@item.PosdetailId">Delete</a>
                                    </td>
                                </tr>
                            }
                        </tbody>
                    </table>



                </div>
            </div>
        </div>
    </div>
</form>
    @section Scripts
        {
        <link href="https://cdn.datatables.net/1.10.15/css/dataTables.bootstrap.min.css" rel="stylesheet" />
        <script src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js"></script>
        <script src="https://cdn.datatables.net/1.10.15/js/dataTables.bootstrap4.min.js "></script>

        <script type="text/javascript">
            $(document).ready(function () {

                $('#posdet-data-table').DataTable({ "order": [[0, "desc"]] });

            });
        </script>



    }



using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using ThePositionerRazor2.Models;

namespace ThePositionerRazor2.Pages.PositionDetail
{
    public class IndexModel : PageModel
    {
        private readonly ThePositionerRazor2.Models.WorkManagerV4Context _context;

        public IndexModel(ThePositionerRazor2.Models.WorkManagerV4Context context)
        {
            _context = context;
        }


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

        public async Task OnGetAsync(int? ID, string SelectedPosition)

        {


            if (ID != null)
            {
                Posdetail = await _context.Posdetail
                .Include(p => p.Importance)
                .Include(p => p.KnowdepthNavigation)
                .Include(p => p.Position)
                .Include(p => p.TimeSpentNavigation)
                .Include(p => p.WorkitemNavigation)
        .Where(p => p.Position.PositionId == ID)
         .ToListAsync();
            }
            else
            {
                Posdetail = await _context.Posdetail
                    .Include(p => p.Importance)
                    .Include(p => p.KnowdepthNavigation)
                    .Include(p => p.Position)
                    .Include(p => p.TimeSpentNavigation)
                    .Include(p => p.WorkitemNavigation)
                    .Where(p => p.Position.PositionNbr == SelectedPosition)
                    .ToListAsync();
            }
        }
        public async Task OnPostAsync(string SelectedPosition)
        {
            Posdetail = await _context.Posdetail
                .Include(p => p.Importance)
                .Include(p => p.KnowdepthNavigation)
                .Include(p => p.Position)
                .Include(p => p.TimeSpentNavigation)
                .Include(p => p.WorkitemNavigation)
                .Where(p => p.Position.PositionNbr == SelectedPosition)
                .ToListAsync();

        }


    }
}

职位详情创建

@page
@model ThePositionerRazor2.Pages.PosDetailList.CreateModel

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

<h1>Create</h1>

<h4>Posdetail</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="Posdetail.PositionId" class="control-label"></label>
                <select asp-for="Posdetail.PositionId" class="form-control"
                        
                        asp-items="ViewBag.PositionId">
                </select>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.Workitem" class="control-label"></label>
                <select asp-for="Posdetail.Workitem" class ="form-control" asp-items="ViewBag.Workitem"></select>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.TimeSpent" class="control-label"></label>
                <select asp-for="Posdetail.TimeSpent" class ="form-control" asp-items="ViewBag.TimeSpent"></select>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.ImportanceId" class="control-label"></label>
                <select asp-for="Posdetail.ImportanceId" class ="form-control" asp-items="ViewBag.ImportanceId"></select>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.TimeNrmz" class="control-label"></label>
                <input asp-for="Posdetail.TimeNrmz" class="form-control" />
                <span asp-validation-for="Posdetail.TimeNrmz" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.Knowdepth" class="control-label"></label>
                <select asp-for="Posdetail.Knowdepth" class ="form-control" asp-items="ViewBag.Knowdepth"></select>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.Need" class="control-label"></label>
                <input asp-for="Posdetail.Need" class="form-control" />
                <span asp-validation-for="Posdetail.Need" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.TimeCalc" class="control-label"></label>
                <input asp-for="Posdetail.TimeCalc" class="form-control" />
                <span asp-validation-for="Posdetail.TimeCalc" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.Postskval" class="control-label"></label>
                <input asp-for="Posdetail.Postskval" class="form-control" />
                <span asp-validation-for="Posdetail.Postskval" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.Ftetime" class="control-label"></label>
                <input asp-for="Posdetail.Ftetime" class="form-control" />
                <span asp-validation-for="Posdetail.Ftetime" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.Ftesal" class="control-label"></label>
                <input asp-for="Posdetail.Ftesal" class="form-control" />
                <span asp-validation-for="Posdetail.Ftesal" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Posdetail.Lastupdated" class="control-label"></label>
                <input asp-for="Posdetail.Lastupdated" class="form-control" />
                <span asp-validation-for="Posdetail.Lastupdated" class="text-danger"></span>
            </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");}
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using ThePositionerRazor2.Models;

namespace ThePositionerRazor2.Pages.PosDetailList
{
    public class CreateModel : PageModel
    {
        private readonly ThePositionerRazor2.Models.WorkManagerV4Context _context;

        public CreateModel(ThePositionerRazor2.Models.WorkManagerV4Context context)
        {
            _context = context;
        }

        public IActionResult OnGet(int PositionID)
        {
            int ID = 5;
        ViewData["ImportanceId"] = new SelectList(_context.Imp, "ImportanceId", "ImportanceId");
        ViewData["Knowdepth"] = new SelectList(_context.Knowdep, "DepthId", "DepthId");
        ViewData["PositionId"] = new SelectList(_context.Possummary, "PositionId", "PositionNbr", PositionID);
          

            ViewData["TimeSpent"] = new SelectList(_context.Timescale, "TimevalId", "TimevalId");
        ViewData["Workitem"] = new SelectList(_context.Workhier, "Workitemid", "Workitemid");
            return Page();
        }

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

        // To protect from overposting attacks, 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.Posdetail.Add(Posdetail);
            await _context.SaveChangesAsync();

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

the navigation back to the child list page results in an error

ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')

要修复错误,您可以尝试通过修改以下代码将选定的 PositionId 通过路由值传递到索引页面。

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

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

    var positionId = Posdetail.PositionId;

    return RedirectToPage("./Index", new { ID = positionId });
}