General Scheme for Editing
(see the linked video for explanation)
First add a 2-way bind property, say, [BindProperty]public Product Prod { get; set; }
to your backing class for the model you want to edit. For 2-way bindings see (C# ASP.NET Core) Getting Started with Database INSERT of Form data
- A user clicks an "edit" link and passes the primary key id of the record to a function called, say,
OnGetEdit(int? id)
in your backing class. - Inside this function, the "id" is used to select the specific record from the database, and set the 2-way binding property (say,
Prod
). The response is, then, redirected to the same page. - When the form is rendered, the current data of the record is now presented there, and the user can make changes and post it to a handler called, say,
OnPost
in your backing class. - Inside
OnPost
, theDbContext
is used to set the state of the record (called, say,Prod
as above) to "Modified" as below:// set the state of the item as dirty _ctx.Attach(Prod).State = EntityState.Modified; // it is assumed above that the DbContext // is available as _ctx // update the changes _ctx.SaveChanges();
How to use the same form for INSERT and UPDATE
The screenshot shows a simple form that is used for INSERT-ing a new record. The records are displayed on the same page, just below the form. Each record has an "edit" link adjacent to it. When the link is clicked, the data is transferred to the form, and now the same form is used for UPDATE-ing the record.
Dual role of the form: When the form is POSTED and submitted, a 2-way binding property carries the data to the backing class. The handler OnPost
differentiates an "insert" request from an "update" request on the basis of the primary key id of the record. If the id is un-specified, then it is an "insert" operation, but if the id contains some specific value, then it is an update operation.
Video Explanation with a Working Example
Please watch the following youtube video:
Pre-requisites for this Walkthrough
You should already have completed the tutorial on display of data - (C# ASP.NET Core) Displaying Data and OnGetAsync
Step 1 of 2: Index.cshtml Razor Page
(see the linked video for details)
As you can see below each record has an "edit" link attached to it. The handler connected to this link is also, co-incidentally, named Edit
, but could be any convenient name.
@page "{handler?}/{id?}" @model Modular.Pages.IndexModel @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <form method="post"> Name: <input asp-for="Prod.Name" /> <input asp-for="Prod.ID" type="hidden" /> <input type="submit" /> </form> <h1>Display of Data</h1> @foreach (var prod in Model.Products) { <div> @prod.Name | <a asp-route-id="@prod.ID" asp-page-handler="Delete">Delete</a> | <a asp-route-id="@prod.ID" asp-page-handler="Edit">Edit</a> </div> <hr /> }
Step 2 of 2: Index.cshtml.cs backing class file
(see the linked video for details)
Following is the code for the backing class. Notice the handler Edit
is prefixed as OnGetEdit
, because the request is a GET request, and ASP.NET Core requires that OnGet be prefixed to the name of the function.
using DBaseCon; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Threading.Tasks; namespace Modular.Pages { public class IndexModel : PageModel { private readonly ProductContext _ctx; // dependency injection of the ProductContext public IndexModel(ProductContext ctx) { _ctx = ctx; } // for Display/ Sql SELECT public IList<Product> Products { get; set; } // when the page loads public async void OnGetAsync() { // using Microsoft.EntityFrameworkCore; Products = await _ctx.Products.ToListAsync(); } // 2-way binding for Sql INSERT/UPDATE [BindProperty] public Product Prod { get; set; } // handler for each Edit link public async Task<IActionResult> OnGetEdit(int? id) { if (null == id) { // sends 404 error return NotFound(); } Product p = await _ctx.Products.FindAsync(id); // concurrency check if someone deleted the record if (p != null) { // set the bind property Prod = p; } // fill the products collection Products = await _ctx.Products.ToListAsync(); // Model and bind properties are filled // render the page now return Page(); } // handler for form submit public ActionResult OnPost() { // new record if ID un-specified if (default == Prod.ID) { _ctx.Products.Add(Prod); } // updation else { // mark dirty _ctx.Attach(Prod).State = EntityState.Modified; } _ctx.SaveChanges(); // redirect and show the // form again return RedirectToPage(); } // Delete the record Sql DELETE public async Task<IActionResult> OnGetDelete(int? id) { if (null == id) { // sends 404 error return NotFound(); } // query the DbSet for the item to delete var prod = await _ctx.Products.FindAsync(id); // mark from removal from DbSet _ctx.Products.Remove(prod); // cause the deletion await _ctx.SaveChangesAsync(); return RedirectToPage(); } } }
This Blog Post/Article "(C# ASP.NET Core) Editing Records on the same Razor Page with EF Core" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.