Entity Framework API Put method, only update one column - asp.net

I am using Entity Framework API and I am trying to update just one column using the Put method...
[ResponseType(typeof(void))]
[Authorize]
public IHttpActionResult PutLCTimeSlots(int id, LCTimeSlots lCTimeSlots)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != lCTimeSlots.id)
{
return BadRequest();
}
db.Entry(lCTimeSlots).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!LCTimeSlotsExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
My question, what do I need to change in this method to only update one column?
I have tried replacing db.Entry(lCTimeSlots).State = EntityState.Modified; with db.Entry(lCTimeSlots).Property(x => x.taken).IsModified = true; But that didn't work....anyone have any ideas?

You shouldn't use the default PUT for such an operation as it implies a client should be able to update more than a single property. I'd suggest a PUT operation using a route that describes the property being updated w/ parameter of the property's type instead of an LCTimeSlots object:
[HttpPut( "{id}/yourProperty" )]
[Authorize]
public IHttpActionResult YourProperty( int id, TypeOfProperty yourProperty )
{
// validate value of `yourProperty` if you can before loading entity from DB
// load entity from DB
var loadedEntity = dbContext.Set<LCTimeSlots>().Find( id );
// if not found, 404 it
// update property, e.g.:
loadedEntity.YourProperty = yourProperty;
// validate entity in its entirety if necessary
// save changes
}

I'll start by suggesting use of the PATCH verb if you only want to modify certain properties.
Also, it's not a great idea to accept an entity object from the client, instead accept a model object that only has the properties that you aim to modify with this method.
Lastly, verify that the entity exists before attempting to make any change.
Now, do something like this:
var timeSlot = db.LCTimeSlots.SingleOrDefault(e => e.Id == model.Id);
if (timeSlot != null)
{
db.Entry(timeSlot).CurrentValues.SetValues(model);
db.SaveChanges();
}
else
{
//404
}

Related

Put method in web api (EF)

I am using a web api put method. I need to update two columns in the database. But I'm having an issue on updating both column.
I've got an error stated below
System.NullReferenceException: 'Object reference not set to an
instance of an object.'
emp was null.
This is my current code;
public class EmployeeController : ApiController
{
public HttpResponseMessage Put(int id, [FromBody] Employee emp)
{
try
{
using (EmpDBContext dbContext = new EmpDBContext())
{
var entity = dbContext.Employees.FirstOrDefault(e => e.Index == id);
if (entity != null)
{
entity.Name = emp.Name;
entity.EmpNum = emp.EmpNum;
dbContext.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK, entity);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound,
"Employee with Id " + id.ToString() + " not found to update");
}
}
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
}
Need some advice regarding this issue.
When you try to use any value in c# which is null then you will get 'Object reference error'. You need to see the API calling method to check why emp is coming null.
Below are the possibility -
Passing parameter name from calling method should exactly same as the name in parameter of the API, in your case it should be emp.
Check your Employee Model if it matching with your calling method properties.
You can check this info from Network tab of your browser.

How to use Await with LINQ and DTO

I'm just getting to grips with creating a new WebAPI2 project in ASP.NET. I'm trying to get the controller to return data from a DTO I have created rather than the raw object classes that EF created. I've been following a tutorial on Microsoft Docs and have got my method which returns all records to work using the DTO, but I can't figure out how to correctly modify the method which only returns the record with the ID matching the passed parameter using an asynchronous task, like the default method does.
The default method generated by Visual Studio looks like this:
[ResponseType(typeof(Post))]
public async Task<IHttpActionResult> GetPost(int id)
{
Post post = await db.Post.FindAsync(id);
if (post == null)
{
return NotFound();
}
return Ok(post);
}
and I've got my modified method looking like this:
[ResponseType(typeof(PostDTO))]
public async Task<IHttpActionResult> GetPost(int id)
{
var _post = from p in db.Post
where p.PostID == id
select new PostDTO()
{
PostID = p.PostID,
SubmitTime = p.SubmitTime,
SubmitUsername = p.SubmitUsername,
};
if (_post == null)
{
return NotFound();
}
return Ok(_post);
}
This methods works just fine, but as you can see, it doesn't make use of .NET's Await/Async feature to perform the query asynchronously. I'll be honest and admit that I don't actually know if this matters, but I feel like if the default method was asynchronous, so should mine be. I just can't work out where to insert the Async and Await keywords to make this work.
You can use this method as,
[ResponseType(typeof(PostDTO))]
public async Task<IHttpActionResult> GetPost(int id)
{
var _post = await (from p in db.Post
where p.PostID == id
select new PostDTO()
{
PostID = p.PostID,
SubmitTime = p.SubmitTime,
SubmitUsername = p.SubmitUsername,
}).ToListAsync();
if (_post == null)
{
return NotFound();
}
return Ok(_post);
}

ASP.Net Web API Action Result

I'm building an ASP.Net Web API application and i have the following code...
public IHttpActionResult GetCustomers() {
var customers = context.Customers.ToList();
return Ok(customers);
}
I'm using the Ok() method to return customers because i'm using an IHttpActionResult return type.
Now if i have the following method
public void DeleteCustomer(int id) {
var customerInDb = context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null) {
NotFound();
}
context.Customers.Remove(customerInDb);
context.SaveChanges();
}
Can I use NotFound() method here when the return type of my ActionMethod is void???
Void does not have a return type. So you can try to call NotFound(), but I'm not sure if this would even compile - Haven't tried. Why don't you just go with an out of the box IHttpActionResult?
public IHttpActionResult DeleteCustomer(int id)
{
var customerInDb = context.Customers.SingleOrDefault(c => c.Id == id);
if (customerInDb == null)
{
return NotFound();
}
context.Customers.Remove(customerInDb);
context.SaveChanges();
return Ok(customerInDb);
}
Using IHttpActionResult is the more elegant version. If the id is invalid, you can just safely exit your method and tell the calling client that something went wrong. If everything went well, you're just giving the client a thumbs-up. IF you return your deleted entity or just an empty Ok() should not matter at this point.
Using void may or may not delete the entity in your data storage. The client would never know, because the server would not return any response.

How to deserialize

How to deserialize Task response using Json .
public HttpResponseMessage Put(int id, ModelClass modelbject)
{
if (ModelState.IsValid && id == modelbject.modelbjectID)
{
db.Entry(modelbject).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
return Request.CreateResponse(HttpStatusCode.NotFound);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
I want to derialize this and check the IsSuccessStatusCode in my class where i am calling this put method. How can i achieve ?
I want to derialize this and check the IsSuccessStatusCode in my class where i am calling this put method.
You don't have to "deserialize" anything. The method returns an HttpResponseMessage, which has the property you're looking for.
var result = yourController.Put(someId, someObject);
var success = result.IsSuccessStatusCode;
Perhaps the fact that this is a web application is adding some confusion to how you're picturing it. But if you have a class which directly calls this method, then what you get back is simply an HttpResponseMessage object. Which can be inspected just like any other object. No actual web layer is involved in that interaction.

Validating a field based on a different database table / entity

I am writing an MVC 4 application, and using Entity Framework 4.1. I have a validation question which I cannot seem to find the answer to.
Essentially, I have an Entity (object) called "Product" which contains a field "Name", which must follow strict naming conventions which are defined in a separate Entity called "NamingConvention". When the user enters a value, the system needs to check it against the rules established in the NamingConvention entity, and return an error if need be.
Where should this validation be done, and how? I need to check the NamingConvention entity when doing the validation, which means I would need a database context since I'm referencing a different entity. Is there any validation method which won't require me to create a new context? I was thinking of doing the validation in the Controller, since it already creates a data context, but this doesn't seem like the right place to do it.
Thanks for any help!
I have done things like this using a JQuery post (ajax) call from the webpage where the name is being entered. You then post (the value of name) to a method on your controller which can return a JSON value that contains a flag saying if the validation passed and also a message that you want to return to your user. For example :
Javascript in webpage :
$("#name").change(function () {
var nameVal = $(this).val();
$.post(getRoot() + "/NameController/ValidateName", { name: nameVal },
function (data) {
if (data.valid == "true") {
alert("A valid name was chosen");
} else
{
alert(data.message);
}
}, "json");
});
Controller (NameController) Code :
[HttpPost]
public ActionResult ValidateName(string name)
{
// actual validation carried out in a static utility class (Utils.IsNameValid)
// if you are loading the same validation rules from your table each time
// consider caching the data in the application cache or a static List.
bool nameIsValid = Utils.IsNameValid(name, out string ErrorMessage);
JsonResult result = new JsonResult();
result.Data = new { valid = (nameIsValid "true" : "false"), message = ErrorMessage };
return result;
}
I'm using EF 5 but believe you can use this method ... apologies in advance if I'm misleading you with this answer.
You could do the validation within your context (or a context decorator)
public override int SaveChanges()
{
var products = this.GetChangedProducts();
foreach (var product in products)
{
this.ValidateName(product);
}
return base.SaveChanges();
}
private IEnumerable<Product> GetChangedProducts()
{
return (
from entry in _context.ChangeTracker.Entries()
where entry.State != EntityState.Unchanged
select entry.Entity)
.OfType<Product>();
}
private void ValidateName(Product product)
{
//validate here
}

Resources