I have a page with server side rendering using razor, where you can add a couple of elements from different lists, fill some fields and create a request from it on submit.
Each time an item is added/taken from any list, I send a post with submit button to a specific action, e.g. "CustomerSelected". I do this, because I need to recreate additional view components for the added item. In these methods I would like to add added objects to the db context, so on submit I can just say SaveChanges()
and not have to assemble everything in the same method. But in .net core db context is per request and it is advisable to keep it that way. In this case how can I store these temporary entity objects between requests so later if someone decides to submit them I can say SaveChanges()
or discard them otherwise?
I would like to have something like this:
public IActionResult CustomerAdded(int customerId)
{
var customer = _context.Customers.First(c => c.IdCustomer == customerId);
var message = _context.Messages.First(m => m.IdMessage = _idMessage);
message.Customers.Add(customer);
return View();
}
public IActionResult ItemAdded(int itemId)
{
var item = _context.Items.First(c => c.IdItem == itemId);
var message = _context.Messages.First(m => m.IdMessage = _idMessage);
message.Items.Add(item);
return View();
}
public IActionResult Submit()
{
_context.SaveChanges();
return View();
}
If this is not possible then I was thinking about adding individual elements in each method and save them there and onsubmit I would build the last final element. But if someone closes their browser without submitting then I have incomplete data laying in my database. I would have to run some kind of job to delete those and it seems to be too much for such a simple task.
Cookie !
Example links
http://localhost:58603/Home/CustomerAdded/1
http://localhost:58603/Home/CustomerAdded/2
http://localhost:58603/Home/Submit
What about dynamic form(s) with javascript and using
type="hidden"
orvisibility
and then sending everything at onceOr using TempData with redirects and reusing that data in other views(form) as
input type="hidden"
Flow:
Form1 ->
Controller's Method saves data in TempData and Redirects to Form2 View / Or ViewData and return Form2 View? ->
Form2 has TempData inserted into the form under hidden inputs ->
Submit both at once
It's not good idea to use server resources to track changes in such scenarios. In scenarios like shopping basket, list or batch editing it's better track changes at client-side.
Your requirement to get Views generated at server-side doesn't mean you need to track changes in
DbContext
. Get the index view and create view from server, but track changes on client. Then to save, post all data to the server to save changes based on the tracking info that you have.The mechanism for client-side change tracking depends to the requirement and the scenario, for example you can track changes using html inputs, you can track changes using cookie, you can track changes using javascript objects in browser memory like angular scenarios.
Here is this post I'll show an example using html inputs and model binding. To learn more about this topic, take a look at this article by Phill Haack: Model Binding To A List.
Example
In the following example I describe a list editing scenario for a list of customers. To make it simple, I suppose:
To implement above scenario Then you need to create following models, actions and views:
Trackable<T> Model
This class is a model which helps us in client side tracking and list editing:
Customer Model
The customer model:
Index.cshtml View
The Index view is responsible to render
List<Trackable<Customer>>
. When rendering each record, we useRowTemplate
view. The same view which we use when adding new item.In this view, we have a submit button for save and a button for adding new rows which calls Create action using ajax.
Here is Index view:
RowTemplate.cshtml View
This view is responsible to render a customer record. In this view, we first render the
Index
in a hidden, then set a prefix[index]
for the fields and then render the fields, including index again, added, deleted and model id:Here is RowTemplate View:
CustomerController
It will have the following actions.
[GET] Index Action
In this action you can load data from database and shape it to a
List<Trackable<Customer>>
and pass to theIndex
View:[GET] Create Action
This action is responsible to returning new row template. It will be called by a button in Index View using ajax:
[POST] Index Action
This action is responsible for receiving the tracked item from client and save them. The model which it receives is
List<Trackable<Customer>>
. It first strips the validation error messages for deleted rows. Then removes those which are both deleted and added. Then checks if model state is valid, tries to apply changes on data source.Items having
Deleted
property as true are deleted, items havingAdded
as true andDeleted
as false are new items, and rest of items are edited. Then without needing to load all items from database, just using a for loop, calldb.Entry
for each item and set their states and finally save changes.