#c# #.net #asp.net-core
Вопрос:
Я борюсь с созданием представления с помощью операций crud для дочерней коллекции объектов. Попробовал несколько попыток, но на самом деле каждая из них провалилась, так как они не соответствовали моим исключениям.
То, чего я пытаюсь достичь, — это возможность редактировать список элементов в родительском файле, а затем сохранять его через всю форму. Важно то, что я хочу, чтобы пользователи могли манипулировать строками ( OrderPosition
) — обновлять значения, добавлять/удалять строки, а затем решать, сохранять ли родительский элемент вместе со строками или отменять изменения.
Чего я достиг до сих пор, так это того, что изменения в строках отражаются в объекте, который отправляется контроллеру, и правильно сохраняются в бд. Я также могу удалять строки с помощью IsDeleted
prop. (ИМО уродливый)
Класс Order.cs (родительский)
public class Order { public int Id { get; set; } [Display(Name = "Data")] [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] public DateTime OrderDate { get; set; } ...other fields... public virtual Listlt;OrderPositiongt; Positions { get; set; } = new Listlt;OrderPositiongt;(); public Order() { } }
Дочерний элемент OrderPosition.cs
public class OrderPosition { public int Id { get; set; } public string Name { get; set; } public float CostNet { get; set; } public float ValueNet { get; set; } [NotMapped] public bool IsDeleted { get; set; } }
Форма редактирования Edit.cshtml для родителя с редактируемой дочерней таблицей Для дочерней коллекции я использую шаблон редактора Shared/EditorTemplates/OrderPosition.cshtml
@model Models.ApplicationModels.Order lt;form asp-action="Edit"gt; lt;div class="row"gt; lt;div class="col-md-4"gt; @Html.HiddenFor(m =gt; m.Id) lt;div asp-validation-summary="ModelOnly" class="text-danger"gt;lt;/divgt; lt;div class="form-group"gt; lt;label asp-for="@Model.OrderDate" class="control-label"gt;lt;/labelgt; lt;input type="datetime-local" asp-for="@Model.OrderDate" value="@DateTime.Now.ToString("s")" class="form-control" /gt; lt;span asp-validation-for="@Model.OrderDate" class="text-danger"gt;lt;/spangt; lt;/divgt; lt;div class="form-group"gt; lt;input type="submit" value="Update" class="btn btn-primary" /gt; lt;/divgt; lt;/divgt; lt;div class="col-md-8"gt; lt;div class="control-section"gt; lt;table id="positionsTable"gt; lt;theadgt; lt;trgt; lt;thgt;Namelt;/thgt; lt;thgt;Valuelt;/thgt; lt;thgt;Costlt;/thgt; lt;thgt;lt;/thgt; lt;/trgt; lt;/theadgt; lt;tbodygt; @Html.EditorFor(x =gt; x.Positions) lt;/tbodygt; lt;/tablegt; lt;/divgt; lt;/divgt; lt;/divgt; lt;/formgt;
OrderPosition.cshtml editor template for OrderPositions
@model Models.ApplicationModels.OrderPosition @Html.HiddenFor(x =gt; x.Id) lt;trgt; lt;tdgt;@Html.TextBoxFor(x =gt; x.Name, new { @class = "form-control" })lt;/tdgt; lt;tdgt;@Html.TextBoxFor(x =gt; x.ValueNet, new { @class = "form-control" })lt;/tdgt; lt;tdgt;@Html.TextBoxFor(x =gt; x.CostNet, new { @class = "form-control" })lt;/tdgt; lt;tdgt; @Html.HiddenFor(x =gt; x.IsDeleted, new { @class = "isDeletedFlag" }) lt;input type="button" onclick="toDelete.call(this)" class="deleteBtn btn btn-md btn-danger" value="Delete"/gt; lt;/tdgt; lt;/trgt; lt;scriptgt; function toDelete() { $(this).parent().find('.isDeletedFlag').attr('value', 'true'); $(this).parent().parent().hide(); } lt;/scriptgt;
OrderController.cs
This one is also missing some kind of transaction because when calling _orderPositionRepository.RemoveAsync(removedPosition);
the position is then removed from db and changes are saved so I can not revert changes in case anything fails.
[HttpPost] [ValidateAntiForgeryToken] public async Tasklt;IActionResultgt; Edit(Order order) { if (order == null) { return NotFound(); } if (ModelState.IsValid) { try { var notRemovedPositions = order.Positions.Where(x =gt; !x.IsDeleted); var removedPositions = order.Positions.Where(x =gt; x.IsDeleted); foreach(var removedPosition in removedPositions) { await _orderPositionRepository.RemoveAsync(removedPosition); } order.Positions = notRemovedPositions.ToList(); await _repository.UpdateAsync(order); } catch (DbUpdateConcurrencyException) { if (!StatusExists(order.Id)) { return NotFound(); } else { throw; } } return RedirectToAction(nameof(Index)); } return View(order); }
I do not know how to proceed with adding. I would also like to know if there is prettier way to handle this.