.Net Core -предварительное заполнение внешнего (родительского) ключа в дочерней записи из родительского приводит к ошибке в навигации после сохранения ‘создать дочернюю запись’

#c# #asp.net-core #razor-pages

#c# #asp.net-core #razor-страницы

Вопрос:

Привет, у меня есть родительско-дочерние отношения между двумя объектами — 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 возвращается на страницу дочернего списка после сохранения (т.Е. Стандартный код каркаса).
Мой код компилируется без ошибок. Когда я нажимаю кнопку создания страницы создания, запись сохраняет ее в базе данных SQL Server, НО переход обратно на страницу дочернего списка приводит к ошибке.

Ошибка: ArgumentOutOfRangeException: индекс был вне диапазона. Должно быть неотрицательным и меньше размера коллекции. (Параметр «индекс») ThePositionerRazor2.Pages.PositionDetail.Pages_PositionDetail_Index.ExecuteAsync() в Index.cshtml 14. Создать новую

Идея заключается в том, что при возврате в дочерний список возврат будет успешным, и если будет запрошено другое создание, родительский внешний ключ по умолчанию все еще будет действовать.

** Вопросы:

  1. Why am I getting the above error?
  2. How do I have the parent foreign key remain in effect between the list and the create pages upon repeated ‘create’ entries?
  3. Same question as 2- but returning repeatedly to create page with ‘back to list’ as way of navigating out?**

In general I am finding that creating of child records on a different razor page (standard scaffolding using entity framework) leaves a lot to be desired- quite cumbersome when the need to create child records prepopulating the parent foreign key would be a common scenario.

Thoughts?

Below are the cshtml files and cs files for the PositionSummary and PositionDetail

PositionSummary

 @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");
        }
    }
}
 

Ответ №1:

возврат к странице списка дочерних элементов приводит к ошибке

Исключение ArgumentOutOfRangeException: индекс был вне диапазона. Должно быть неотрицательным и меньше размера коллекции. (Параметр «индекс»)

Чтобы исправить ошибку, вы можете попытаться передать выбранное 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 });
}