I know there is a way to do this the "right" way, but for some reason I can't find an answer. I even saw on Microsofts guide that hidden fields are the way to go, but it feels "wrong".
I am finding my update works fine when I put all the hidden fields in the Edit form:
<input type="hidden" asp-for="OrgUnits.Organizations" />
<input type="hidden" asp-for="OrgUnits.Address" />
<input type="hidden" asp-for="OrgUnits.AlternateId" />
<input type="hidden" asp-for="OrgUnits.Category" />
<input type="hidden" asp-for="OrgUnits.City" />
<input type="hidden" asp-for="OrgUnits.FriendlyPath" />
<input type="hidden" asp-for="OrgUnits.IsTop" />
<input type="hidden" asp-for="OrgUnits.Name" />
<input type="hidden" asp-for="OrgUnits.NextChildId" />
<input type="hidden" asp-for="OrgUnits.RecoveryOverride" />
<input type="hidden" asp-for="OrgUnits.RowStatus" />
<input type="hidden" asp-for="OrgUnits.RowVersion" />
<input type="hidden" asp-for="OrgUnits.State" />
<input type="hidden" asp-for="OrgUnits.UseAppVersion" />
<input type="hidden" asp-for="OrgUnits.ZipCode" />
But, that seems like a poor way to write code. I only want a few of the fields in this table to be editable.
Here is my controller:
public async Task<IActionResult> Edit(string id, [Bind("OrgUnits")] OrgUnitsViewModel orgUnitsViewModel)
{
id = Uri.UnescapeDataString(id);
if (id != orgUnitsViewModel.OrgUnits.OrgUnitId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
//Get org for the DbCatalog
var org = await _opkCoreContext.Organizations.FindAsync(orgUnitsViewModel.OrgUnits.OrgId);
_serverConnectionHelper.SetDatabaseConnectStringToSession(org.DbCatalog);
_opkDataContext.Update(orgUnitsViewModel.OrgUnits);
await _opkDataContext.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!OrgUnitsExists(orgUnitsViewModel.OrgUnits.OrgUnitId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index), new { currentSearchFilter = orgUnitsViewModel.OrgUnits.OrgUnitId });
}
return View(orgUnitsViewModel);
}
Is this really how this is supposed to be done. I went the route of AutoMapper, but that was failing for me and I don't quite understand how to use it. Anyways, here is my error:
DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded.
Hopefully one of you smart people out there know the answer. I am surprised I can't find anything on Google or SO because I know this is extremely common. It is just that hidden fleids seems so wrong because what if you miss one?
Thank you very much in advance.
I personally do following For partially update an entity:
If I don't want to send an entire model to action to change entire entity, I would make an endpoint(API action) that partially update entity and return success status code instead of View. I would use ajax request to the endpoint to change the entity without refreshing the page.
This is my code for partially updating a
Employee
entity:Employee.cs
EmployeeUpdateDto.cs
Controller.cs
You must send your request body in the following standard patch format (json):
That's it. the sample request above would change the Employee name to "new_name" and set the Position to its default value (in this case null).
Above sample needs these prerequisites to work:
Microsoft.AspNetCore.JsonPatch to support
JsonPatchDocument
type.Microsoft.AspNetCore.Mvc.NewtonsoftJson to support mapping request to
JsonPatchDocument<T>
. Configure this inConfigureServices()
method:services.AddControllersWithViews .AddNewtonsoftJson();
AutoMapper.Extensions.Microsoft.DependencyInjection to map EmployeeUpdateDto to Employee. Add a mapping profile class and configure AutoMapper in
ConfigureServices()
method:and
In above code we use
CreateMap<EmployeeUpdateDto, Employee>().ReverseMap();
for our needs.