0

I am trying to update the entity only by the values sent to the API dynamically, so each time the client will send to my api different values it will change only the given values.

This is my entity

    public class Administrator
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string Role { get; set; }
        public int Phone { get; set; }
    }

This is my repository:

public Task<bool> UpdateAdmin(Administrator admin)
        {
            if (admin != null)
            {
                _context.Admins.Update(admin);
                Commit();
                return Task.FromResult(true);
            }
            else
            {
                return Task.FromResult(false);
            }
        }

Lets say I want to update only the phone number, I send the data with only new phone number but the rest of the properties are changed to null aswell. How can I update only the given ones?

Thanks

Darmon
  • 303
  • 4
  • 17
  • 1
    First: don't send the entire entity to the client, *especially* not a partially populated one. Use a view model that "knows" which property was modified. Once you have that, there are several ways to make a point update that all boil down to marking one property as modified. – Gert Arnold Jul 05 '20 at 19:52

2 Answers2

1

You will need to use a JsonPatchDocument

here is a sample code of me doing something similar

//get the instance of admin you want to update
var adminInstance = GetAdmin....//get your admin

//partial update -> this how you create a patch doc with C#
var patchDoc = new JsonPatchDocument<Admin>();
patchDoc.Replace(x => x.phone, "put new phone number");//for any other property do x.propertyName
patchDoc.ApplyTo(adminInstance)// apply the patch doc to the instance you want to update
await UpdateAdmin(adminInstance)//your update method look good

//for people trying to do this with an api serialize the patch doc then send it to api
var adminDto =JsonConvert.SerializeObject(patchDoc);



//this is an api example
[HttpPatch("{adminId}")]
public async Task<ActionResult> UpdateAdmin(string adminId, JsonPatchDocument<Admin> patchDocument)
{
  var admin= await _adminRespository.GetAsync(admin);//get the admin you want to update

  patchDocument.ApplyTo(admin); //apply patch doc to the admin

  await _adminRespository.UpdateAsync(admin); //pass admin to your repo

  await _adminRespository.SaveAsync();

  return NoContent();
  }

in the repos you dont have to do anything complicated just pass the model as an update all the work is done by the json patch doc.

To learn more about patch doc

http://jsonpatch.com/

if you can also acheive the same thing with the solution provided in this Entity Framework validation with partial updates

2cool4school
  • 239
  • 4
  • 11
  • What if OP is not using (auto?)mapper? – Guru Stron Jul 05 '20 at 19:26
  • The code I provided is a sample. The OP can get the model from the database and apply the json patch document directly to the model he got from the database. it doesn't make much of any difference. the json patch doc is getting applied to a object of the OP choosing. In my case I choose dto cause it is best pratice. OP dont have to.@GuruStron – 2cool4school Jul 05 '20 at 20:00
  • I don't really understand what is this patch for... My question was, is it possible to update the Administrator object only by the filled values? For example Password and Phone are empty but I don't want the database to make them null but just not change the current values. I hope I explain myself correctly – Darmon Jul 06 '20 at 18:53
  • you can perform the update before you send it to the dbcontext using or you can configure ef to help you do it. or you can do it manually. – 2cool4school Jul 06 '20 at 21:27
1

Update

According to your comment, admin receives different field contents each time.

So you can use reflection to dynamically determine whether the value of each field accepted by admin is null. If not, replace the value of the corresponding field of data.

public Task<bool> UpdateAdmin(Administrator admin)
        {
            if (admin != null)
            {   
                var data = _context.Admins.Find(admin.Id);
               
                Type t = typeof(Administrator);
                PropertyInfo[] propInfos = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (var item in propInfos)
                {
                   var fieldValue = item.GetValue(admin);
                   if (fieldValue != null)
                   {
                      item.SetValue(data, fieldValue);
                   }
                 }

                  _context.Admins.Update(data);
                  Commit();
                  return Task.FromResult(true);
            }
            else
            {
                return Task.FromResult(false);
            }
        }
LouraQ
  • 6,443
  • 2
  • 6
  • 16
  • It's not just by the phone field, but imagine the object Administrator each time will send you different keys. For example first request will be phone and name, second request will be email and password, third one will be only password. But each time I want the repository update ONLY the given values and not the entire object/table. Is that possible or I have to create request for each one by one? – Darmon Jul 06 '20 at 18:50
  • 1
    @Darmon, If you pass in different field values each time, then the best way is to dynamically obtain the name of each field through `reflection` and then determine whether the corresponding value is null. I have modified my reply, hope it can help you. – LouraQ Jul 07 '20 at 02:21
  • I will check it and let you know, thanks @Yongqing Yu – Darmon Jul 07 '20 at 10:22