CRUD для детской коллекции без сохранения в БД

#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.