0

I have a large form about customer details which contains around 50 fields. A customer can update his information, like address and contact number. When he edits his profile, he is presented with all 50 input fields editable. When he edits for example only address field, I want to determine the modified field on the POST so that I send only those fields to the underlying system (SAP).

This is what I have done so far,

  1. Update all 50 fields in the system, because I am unable to determine which fields have been modified.
  2. To determine modified fields only, I maintained 50 more fields in the viewModel and upon post compare relevant fields to determine which fields are modified.

But as obvious, these both methods are poor design practices plus they add extra overhead to performance.

I want to know, how can we determine the modified fields upon POST so that I only send update request for the modified fields only.

Appreciate your insights on this.

Adil Khalil
  • 2,073
  • 3
  • 21
  • 33
  • There are plenty of ways to do this, ranging from having individual requests for each field (in-line editing) to tracking the amended fields in the client via JavaScript and including a list in your POST request. It's quite a broad topic as it stands. – Ant P Nov 24 '14 at 13:03
  • Thank you @AntP, Can you please point me in the right direction? I would like to track the amended fields in the client and grab that info in controller. – Adil Khalil Nov 24 '14 at 13:07
  • If model structure is somehow _simple_ you can do something similar to what explained in this post: [Comparing two objects by iterating recursively through all the properties' properties](http://stackoverflow.com/a/25064247/1207195). – Adriano Repetti Nov 24 '14 at 13:09
  • When a field is changed, add a hidden field with a name of `changed` and a value of the name of the changed field (via JS). Then have a model property with the following signature: `List Changed { get; set; }`. In your post, that list will be populated with the names of the changed fields. – Ant P Nov 24 '14 at 13:10

2 Answers2

1

I have recently encountered with a similar problem while building an API using Web API 2 and EF6.

I have an entity with many fields, and I only want to update the fields that are recieved in the json.

So instead of using the ASP deserializer and receive the object parsed

like so:

public IHttpActionResult Update(int id, Product product) { ... }

I removed the Product from the function call

public IHttpActionResult Update(int id){ ... }

Read the json from the Request body

var rawBody =  Request.Content.ReadAsStringAsync().Result;

Deserializer the json content to a dictionary of field and value

Dictionary<string, string> rawProduct = JsonConvert
              .DeserializeObject<Dictionary<string, string>>(rawBody); 

Build the update object

var product = JsonConvert.DeserializeObject<Product>(rawBody);

Remove the Id key from the update field dictionary

rawProduct.Remove("Id");

Attach the product to the context

dbContext.Products.Attach(product);

Loop through all the properties of the object check which of them is present in the dictionary and set their modified attribute to true.

foreach(var p in product.GetType().GetProperties()){
    if(rawProduct.ContainsKey(p.Name)) {
        dbContext.Entry(product).Property(p.Name).IsModified = true;
    }
} 

Full code:

public IHttpActionResult Update(int id){ 

    var rawBody =  Request.Content.ReadAsStringAsync().Result;

    Dictionary<string, string> rawProduct = JsonConvert
                  .DeserializeObject<Dictionary<string, string>>(rawBody); 

    var product = JsonConvert.DeserializeObject<Product>(rawBody);

    rawProduct.Remove("Id");

    dbContext.Products.Attach(product);

    foreach(var p in product.GetType().GetProperties()){
        if(rawProduct.ContainsKey(p.Name)) {
            dbContext.Entry(product).Property(p.Name).IsModified = true;
        }
    }

    dbContext.SaveChanges(); 
}
Eddy K
  • 216
  • 1
  • 7
0

Similar to the solution from @klimslava . The difference is that instead of setting property's IsModified to true. I read the current Product, and then set the value to it. Otherwise, you will get DbEntityValidationException

public IHttpActionResult Update(int id){ 
    var rawBody =  Request.Content.ReadAsStringAsync().Result;

    Dictionary<string, string> rawProduct = JsonConvert
              .DeserializeObject<Dictionary<string, string>>(rawBody); 

    var product = JsonConvert.DeserializeObject<Product>(rawBody);

    rawProduct.Remove("Id");

    var currentProduct = dbContext.Products.Find(product.Id);

    foreach(var p in product.GetType().GetProperties()){
        if(rawProduct.ContainsKey(p.Name)) {
            p.SetValue(currentDocument, p.GetValue(document));
        }
    }

    dbContext.SaveChanges(); 
}
rocksoccer
  • 71
  • 1
  • 7