Мне пришлось перейти от формы с одной записью к таблице с несколькими записями. У меня есть таблица, работающая с точки зрения полей/форматов даты/удаления строки и добавления кнопок строки (с помощью GitHub Copilot).
Моя проблема в том, что я не могу сохранить записи «Создать» при нажатии любой из кнопок «Создать». Я попытался изменить возвращаемое представление (viewModel) обратно на возвращаемое представление (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 ... he-data-to
Почему нажатие на кнопку «Сохранить» обновляет мою модель представления, но не сохраняет данные в моем списке? ⇐ C#
Место общения программистов C#
1763491080
Anonymous
Мне пришлось перейти от формы с одной записью к таблице с несколькими записями. У меня есть таблица, работающая с точки зрения полей/форматов даты/удаления строки и добавления кнопок строки (с помощью GitHub Copilot).
Моя проблема в том, что я не могу сохранить записи «Создать» при нажатии любой из кнопок «Создать». Я попытался изменить возвращаемое представление (viewModel) обратно на возвращаемое представление (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[i] ?? 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
Подробнее здесь: [url]https://stackoverflow.com/questions/79823399/why-does-clicking-on-my-save-button-update-my-viewmodel-but-not-save-the-data-to[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия