Update Database in C# after using JsonPatchDocument.ApplyTo - c#

So here is my problem. I have an httpPatch endpoint where I have to do an update.
Here is the code
[HttpPatch, Route("api/serversTarget/{id}")]
public IHttpActionResult updateEntity(int id, [FromBody] JsonPatchDocument<ServerTarget> patchEntity)
{
var entity = db.getAllServers().FirstOrDefault(s => s.id == id);
if (entity == null)
{
return NotFound();
}
patchEntity.ApplyTo(entity);
//UPDATE in Oracle Database
db.updateServerInDatabase(entity);
return Ok(entity);
}
I get all the db entries when the program starts and put them into a list (getAllServers()). My question is how do I know what changes have been made by patchEntity.ApplyTo() so I can update the database accordingly.

Related

Partially update a complex object in Entity Framework Core in a web api

I'm having issues trying to update a rather complex object in an ASP.NET Core Web API.
I changed my put method to the following code:
[Authorize(Policy = "IsAuthor")]
[HttpPut("{id}")]
public async Task<IActionResult> PutCIApplication([FromRoute] Guid id, [FromBody] CIApplication cIApplication)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != cIApplication.ID)
{
return BadRequest();
}
string userLang = HttpContext.Request.Headers["UserCulture"].ToString();
cIApplication.Translations[userLang].Name = cIApplication.Name;
cIApplication.Translations[userLang].Description = cIApplication.Description;
var dbCIApplication = await _context.CIApplications.Include(c => c.Translations)
.Include(c => c.DeploymentScenarios).ThenInclude(d => d.InstallSequence).ThenInclude(s => s.Steps).ThenInclude(s => s.SubSteps)
.Include(c => c.DeploymentScenarios).ThenInclude(d => d.UninstallSequence).ThenInclude(s => s.Steps).ThenInclude(s => s.SubSteps)
.Include(c => c.SoftwareMeteringRules).Include(c => c.Catalogs).Include(c => c.Categories)
.AsNoTracking()
.SingleOrDefaultAsync(m => m.ID == id);
HashSet<string> excludedProperties = new HashSet<string>();
excludedProperties.Add("OwnerCompanyID");
excludedProperties.Add("OwnerCompany");
excludedProperties.Add("CreatedDate");
excludedProperties.Add("CreatedBy");
excludedProperties.Add("UpdatedDate");
excludedProperties.Add("UpdatedBy");
var patch = JsonPatchCreation.CreatePatch(dbCIApplication, cIApplication, excludedProperties);
if ((await _authorizationService.AuthorizeAsync(User, cIApplication, "CIAuthoringManagement")).Succeeded)
{
patch.ApplyTo(dbCIApplication);
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CIApplicationExists(id))
{
return NotFound();
}
else
{
throw;
}
}
catch (Exception)
{
throw;
}
return NoContent();
}
else
{
return Unauthorized();
}
}
As you can see, the CIApplication class contains lots of relationships with other classes and dependent themselves have a lot of relations.
This controller action works fine with a simple object which doesn't have any relations.
But in this case, the controller doesn't throw any exception, but the object isn't updated in database.
I first tried without the .AsNoTracking, but in this case I have an exception saying that a DeploymentScenarios is already tracked.
I want to do a partial update because some relations aren't sent to my native client by the get action (in this case OwnerCompany) and so when the object is sent for update the navigation property have a null value and thus EF Core removes the relation.
If someone have an idea on how to make it work in the most simplest way it would be great !
Thanks !

.NET Core 2.0 MVC - Programmatically change values before calling TryUpdateModelAsync

I have been following this tutorial on .NET Core CRUD operations https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/crud Below is my Edit method
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditUser(string id, ApplicationUser applicationUser)
{
if (id != null)
{
return NotFound();
}
var userToUpdate = await _context.ApplicationUser.SingleOrDefaultAsync(u => u.Id == id);
if(await TryUpdateModelAsync<ApplicationUser>(
userToUpdate,"",m => m.DateUpdated,m=> m.Name, m=>m.Email))
{
try
{
if (applicationUser.IsAdmin)
{
var x = await _userManager.AddToRoleAsync(applicationUser, "Admin");
if (!x.Succeeded)
{
}
}
else
{
await _userManager.AddToRoleAsync(applicationUser, "User");
}
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
catch(DbUpdateException ex)
{
//TODO: err
}
return View(applicationUser);
}
}
However, there is no clear documentation on how to then update the fields programmatically before calling the Update using the TryUpdateModelAsync method. For example, I want to set the DateUpdated. Or what if I wanted to make some other field change based on the form value?
The method TryUpdateModelAsync just updates properties of the userToUpdate and doesn't save to database anything. The properties listed in method params should be in the controller's current IValueProvider(e.g. in FormValueProvider)
I want to set the DateUpdated
If you want to change additional properties that are not exist in the form you can do it anywhere but before the entity will be saved by await _context.SaveChangesAsync();:
userToUpdate.DateUpdated = DateTime.Now;
Or what if I wanted to make some other field change based on the form value?
you can get form values from HttpContext.Request.Form:
userToUpdate.SomeProperty = HttpContext.Request.Form["SomeProperty"];

ASP.NET Entity Framework API Update single column

I am using ASP.NET MVC Entity Framework and I created an API controller, now I want to add a method that is basically a copy of the put method, however I want to adjust this method so it updates a single column
[ResponseType(typeof(void))]
[Authorize]
public IHttpActionResult PutUser(int id, Users user)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != user.id)
{
return BadRequest();
}
db.Entry(user).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!UsersExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
each user in my User class has an email and column called isOnline, for this method I want to update the isOnline to true based on the email.
The examples I have seen online are for non API controllers. Please Help!
Your subject is partial update in Entity Framework, following is an example:
var user= new User() {Id = id, TargetColumn = "test"};
context.Users.Attach(user);
var entry = context.Entry(user);
entry.Property(e => e.TargetColumn ).IsModified = true;;

Updating entity using DBcontext in entity framewok is not working

I have a project I am using a database that is connected thru the entity data model and I am using the DBcontext to create and update entities.
My Create method (below) is working fine.
[HttpPost]
public IHttpActionResult PostCustomer([FromBody] Customer Customer)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
using (var dbCtx = new CustomerDBEntities())
{
dbCtx.Customers.Add(Customer);
dbCtx.SaveChanges();
}
return CreatedAtRoute("DefaultApi", new { id = Customer.id }, Customer);
}
But my update method is doing nothing. I am not getting an error or anything just nothing seems to happen. and it is not updating the values.
The code is this
[HttpPut]
public IHttpActionResult UpdateCustomer([FromBody] Customer Customer)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Customer cust;
var ctx = new CustomerDBEntities();
cust = ctx.Customers.Where(s => s.id == Customer.id).FirstOrDefault<Customer>();
if (cust != null)
{
cust.Customer_Name = Customer.Customer_Name;
cust.email = Customer.email;
cust.Customer_address = Customer.Customer_address;
}
ctx.Entry(cust).State = System.Data.EntityState.Modified;
ctx.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = Customer.id }, Customer);
}
When I was using an SQL command before to go directly to database it was working fine but ever since I changed it it stopped working.
Any help would be much appreciated.
Remove this line of code.
ctx.Entry(cust).State = System.Data.EntityState.Modified;
EF tracks the changes made to entities in the context, you do not need to tell it that it was modified.
Add changes at Property Level
context.Entry(Customer).Property(cust => cust.Customer_Name).IsModified = true;
More Details here https://msdn.microsoft.com/en-us/data/jj592677
Also similar question answered here https://stackoverflow.com/a/15339512/1481690

Saving Entity Framework object is deleting existing one

I have an information page which is being posted to database using Entity Framework. Everything is fine but when I initially enter a record and hit save twice, the record is deleted from database (it actually saves after first save click). This problem doesn't reflect for modifying and occurs for new entry.
Here is my code
public async Task<IHttpActionResult> Put(int id, [FromBody]CandidateLanding landing)
{
var result = await candidateContext.CandidateLanding
.Where(x => x.UserID == id)
.AsNoTracking()
.SingleOrDefaultAsync();
if (result != null)
{
if (landing.ID == 0)
{
landing.ID = result.ID;
}
}
if (ModelState.IsValid)
{
if (landing.ID > 0)
{
candidateContext.Entry(landing).State = EntityState.Modified;
}
else
{
landing.UserID = id;
candidateContext.CandidateLanding.Add(landing);
}
await candidateContext.SaveChangesAsync();
}
return CreatedAtRoute("DefaultApi", new { id = landing.ID }, landing);
}

Categories

Resources