I am using AutoMapper and this is my code to update the details of an existing customer but when I update one field the rest of the fields get nulled.
public async Task<ResponseModel> Update(CustomerDTO customer, int id)
{
ResponseModel responseModel = new ResponseModel();
try
{
Customer? existingCustomer = await _dbContext.FindAsync<Customer>(id);
if (existingCustomer == null)
{
return new ResponseModel()
{
IsSuccess = false,
Message = $"Customer doesn't exist!"
};
}
_mapper.Map(customer, existingCustomer);
if (await _dbContext.SaveChangesAsync() > 0)
{
responseModel.Message = "Customer Updated Successfully";
responseModel.IsSuccess = true;
}
}
catch (Exception ex)
{
responseModel.IsSuccess = false;
responseModel.Message = $"Error:{ex.Message}";
}
return responseModel;
}
Here’s the mapper profile:
using AutoMapper;
using static MGApi.Services.CustomerService;
namespace MGApi.Models
{
public class CustomerProfile : Profile
{
public CustomerProfile()
{
CreateMap<CustomerDTO, Customer>();
}
}
}
I tried adding using ForAllOtherMembers
but it is deprecated. I’m not sure how to solve this.
Here is the Customer Model:
using System.ComponentModel.DataAnnotations;
namespace MGApi.Models
{
public class Customer
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(50)]
[RegularExpression(@"^d{10}$", ErrorMessage = "Invalid phone number")]
public string? PhoneNumber { get; set; }
[Required]
[StringLength(50)]
public string? Name { get; set; }
[StringLength(100)]
[EmailAddress]
public string? Email { get; set; }
[StringLength(10)]
public string? Gender { get; set; }
[DataType(DataType.Date)]
public DateTime DateOfBirth { get; set; }
public ICollection<CustomerData>? CustomerData { get; set; }
}
}
Now below we have the CustomerData Model which has a foreign key based on the primary key of the Customer Model:
using System.ComponentModel.DataAnnotations;
namespace MGApi.Models
{
public class CustomerData
{
[Key]
public int Id { get; set; }
public int CustomerId { get; set; }
public double Sugar { get; set; }
public double BP { get; set; }
public double Height { get; set; }
public double Weight { get; set; }
public DateTime Timestamp { get; set; } = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("India Standard Time"));
public Customer? Customer { get; set; }
}
}
2
Answers
So most of the data on your
Customer
is nullable, you haven’t addedCustomerDTO
but I can assume that names of properties are same as inCustomer
. You are only passing one value in body of your request lets saySo
CustomerDTO
that is created from it will look something like that:After mapping that you perform values will be same and will be saved to the database like that as well. This is how update request works in general. You’re taking old object, change one(or more) value and pass new object with changed value(s).
If you want to change one value like you do right now you should look into:
https://learn.microsoft.com/en-us/aspnet/core/web-api/jsonpatch?view=aspnetcore-7.0
In my opinion implementing
JsonPatch
is not worth the time unless you need to ensure that changes made by two users won’t be overwriten. In other cases simple update is enough and you should just change how you consumer your API – pass all the needed data.I think it is because of your nullable fields in
Customer
andCustomerDto
and bunch of fields ofCustomerDto
instance arenull
.I have two solutions for your problem:
First, use
JsonPatch
for partial updating.Second, prevent mapping
null
values from source to destination by changing you mapping profile as follows: