Почему нажатие кнопки «Сохранить» обновляет мою модель представления, но не сохраняет данные в моем списке?C#

Место общения программистов C#
Ответить
Anonymous
 Почему нажатие кнопки «Сохранить» обновляет мою модель представления, но не сохраняет данные в моем списке?

Сообщение Anonymous »

Мне пришлось перейти от формы с одной записью к таблице с несколькими записями. У меня есть таблица, работающая с точки зрения полей/форматов даты/удаления строки и кнопок добавления строки (с помощью GitHub Copilot).
Моя проблема в том, что я не могу сохранить записи «Создать» при нажатии любой из кнопок «Создать». Я попытался изменить return View (viewModel) обратно на return View (docTrailList), но это не дало никакого эффекта.
Вот модель DocTrailList вместе с DocTrailListDetail, которая используется для таблицы:

using System.ComponentModel.DataAnnotations;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace Research.Models
{
public class DocTrailList
{
[Key]
public int DetailID { get; set; }

[ForeignKey("ProjectID")]
public int? ProjectID { get; set; }

[Display(Name = "Document Type")]
public string? DocumentType { get; set; }

public string? Version { get; set; }

[DataType(DataType.Date)]
public DateTime? Dated { get; set; }

[Display(Name = "Date Received")]
[DataType(DataType.Date)]
public DateTime? DateReceived { get; set; }

[Display(Name = "Is This Current?")]
public string? IsThisCurrent { get; set; }

[ForeignKey("ProjectID")]
public PIF? PIF { get; set; }
}

public class DocTrailListDetail
{
[ForeignKey("ProjectID")]
public int? ProjectID { get; set; }

public List? Docs { get; set; }

[ForeignKey("ProjectID")]
public PIF? PIF { get; set; }
}
}

Вот метод Create контроллера:
// GET: DocTrailLists/Create
[HttpGet]
public IActionResult Create([FromQuery] int projectID)
{
ViewBag.ProjectIDList = new SelectList(_context.PIF!.ToList(), "ProjectID", "ProjectID");
var viewModel = new DocTrailListDetail { Docs = new List { new DocTrailList() } };

ViewBag.dtname = _context.DocType!.ToList();
ViewBag.current = new SelectList(_context.YesNoList!.ToList(), "YesNo", "YesNo");

return View(viewModel);
}

public Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary GetModelState()
{
return ModelState;
}

// POST: DocTrailLists/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task Create(DocTrailListDetail viewModel, [Bind("DetailID,ProjectID,DocumentType,Version,Dated,DateReceived,IsThisCurrent")] DocTrailList docTrailList,
string action,
string returnUrl, [FromQuery] int projectID)
{
// Use existing single-item validator to validate each item in the viewModel
var perItemValidator = new DocTrailListsValidator(_context);
var aggregatedFailures = new List();

if (viewModel?.Docs != null && viewModel.Docs.Count > 0)
{
for (int i = 0; i < viewModel.Docs.Count; i++)
{
var item = viewModel.Docs ?? new DocTrailList();
var itemResult = perItemValidator.Validate(item);

foreach (var failure in itemResult.Errors)
{
// Map property name so model binding associates error with the correct list element
var propName = string.IsNullOrEmpty(failure.PropertyName)
? $"Docs[{i}]"
: $"Docs[{i}].{failure.PropertyName}";
aggregatedFailures.Add(new ValidationFailure(propName, failure.ErrorMessage)
{
AttemptedValue = failure.AttemptedValue
});
}
}
}
else if (docTrailList != null)
{
// Fallback to validating the single docTrailList parameter when posted separately
var singleResult = perItemValidator.Validate(docTrailList);
aggregatedFailures.AddRange(singleResult.Errors);
}

var result = new ValidationResult(aggregatedFailures);

// Populate ModelState with validation failures so the view can render errors
if (!result.IsValid)
{
foreach (var failure in result.Errors)
{
ModelState.AddModelError(failure.PropertyName, failure.ErrorMessage);
}
}

// When validation failed, return to Create View with prepared viewModel and select lists
if (!ModelState.IsValid)
{
// If the binder gave us a single DocTrailList via the separate parameter, use it.
// This preserves any posted DetailID instead of forcing a new blank row.
if ((viewModel?.Docs == null || viewModel.Docs.Count == 0) && docTrailList != null)
{
viewModel = viewModel ?? new DocTrailListDetail();
viewModel.Docs = new List { docTrailList };
}
else if (viewModel == null)
{
viewModel = new DocTrailListDetail { Docs = new List { new DocTrailList() } };
}
else if (viewModel.Docs == null || viewModel.Docs.Count == 0)
{
// fall back to a blank row only if nothing was posted
viewModel.Docs = new List { new DocTrailList() };
}

ViewData["ProjectIDList"] = new SelectList(_context.PIF!.ToList(), "ProjectID", "ProjectID");
ViewBag.ProjectIDList = new SelectList(_context.PIF!.ToList(), "ProjectID", "ProjectID");
ViewBag.current = new SelectList(_context.YesNoList!.ToList(), "YesNo", "YesNo");

var dtname = _context.DocType!.ToList();
ViewBag.dtname = dtname;

ViewBag.current = new SelectList(_context.YesNoList!.ToList(), "YesNo", "YesNo");

return View(viewModel);
}

// Build list of items to save (either the posted list or the single item)
List toSaveList = new List();

if (viewModel?.Docs != null && viewModel.Docs.Count > 0)
{
// Add non-null entries (optionally filter out completely empty rows if desired)
toSaveList.AddRange(viewModel.Docs.Where(d => d != null));
}
else if (docTrailList != null)
{
toSaveList.Add(docTrailList);
}

if (toSaveList.Count == 0)
{
// Nothing to save; redirect back to index (or return view). Preserve existing behavior: redirect to Index.
return RedirectToAction(nameof(Index));
}

// Perform DB update after validation is passed
if (action == "SaveAndBack" && !String.IsNullOrEmpty(returnUrl))
{
try
{
_context.AddRange(toSaveList);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
// Attempt to provide similar fallback behavior as before
var idToCheck = docTrailList?.DetailID ?? viewModel?.Docs?.FirstOrDefault()?.DetailID ?? 0;

if (!DocTrailListExists(idToCheck))
{
return NotFound();
}
else
{
throw;
}
}

// Redirect back to PIF details for the ProjectID on the posted viewModel (prefer viewModel.ProjectID)
var redirectProjectId = viewModel?.ProjectID
?? toSaveList.FirstOrDefault(d => d.ProjectID.HasValue)?.ProjectID
?? docTrailList?.ProjectID;

var redirectUrl = Url.Action("Details", "PIFs", new { id = redirectProjectId });

if (string.IsNullOrEmpty(redirectUrl))
{
return NotFound(); // Handle the case where the URL could not be generated
}

return Redirect(redirectUrl);
}
else
{
try
{
_context.AddRange(toSaveList);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
var idToCheck = docTrailList?.DetailID ?? viewModel?.Docs?.FirstOrDefault()?.DetailID ?? 0;

if (!DocTrailListExists(idToCheck))
{
return NotFound();
}
else
{
throw;
}
}

return RedirectToAction(nameof(Index));
}
}

А вот часть кнопки создания Create.cshtml:



@* Hidden field named 'action' keeps server-side expectation while avoiding an element named 'action' that can shadow form.action in the DOM. *@



 
 
Create and go back to the PIF
 
 
Back to List



Подробнее здесь: https://stackoverflow.com/questions/798 ... t-save-the
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»