Please see my original SO question here - Entity Framework Core - efficient way to update Entity that has children based on JSON representation of entity being passed in via Web API
This question details that I'm building an API using .NET Core, Entity Framework Core and PostgreSQL. I am trying to bring in an object via the API, convert it to a type of Customer entity, then use it to update an existing Customer entity so basically take all the modified properties that have changed between the original and update, and generate an update statement.
This has failed, due to the below error:
System.InvalidOperationException: The property 'CustomerInternalId' on entity type 'Customer' is part of a key and so cannot be modified or marked as modified. To change the principal of an existing entity with an identifying foreign key first delete the dependent and invoke 'SaveChanges' then associate the dependent with the new principal.
I am unclear however, how I can perform the update while asking .NET Core / EF Core to just keep the primary key CustomerInternalId of the existing record?
Obviously I don't want to change the primary key, that's probably the one thing I don't ever want to update. It's all the other properties that may be changed by the incoming data.
Here's my sample method (it's half way through testing so there's bits of logging etc in there as I'm trying to figure this out).
/// <summary>
/// Update customer record - still working on this
/// </summary>
/// <param name="customerPayload"></param>
public static void UpdateCustomerRecord(CustomerPayload customerPayload)
{
try
{
var updateCustomer = customerPayload.Convert(customerPayload);
Console.WriteLine($"Update customer created from payload");
using (var loyalty = new loyaltyContext())
{
Console.WriteLine($"Using context to get db customer by mca id {updateCustomer.McaId}");
var customer = loyalty.Customer
.Include(c => c.ContactInformation)
.Include(c => c.Address)
.Include(c => c.MarketingPreferences)
.Include(c => c.ContentTypePreferences)
.Include(c => c.ExternalCards)
.Where(c => c.McaId == updateCustomer.McaId).First();
var cu = (from c in loyalty.Customer
where c.McaId == updateCustomer.McaId
select c).ToList();
Console.WriteLine($"Customer guid from linq query {cu.First().CustomerInternalId}");
Console.WriteLine(
$"db customer Id {customer.CustomerInternalId} incoming customer Id {updateCustomer.CustomerInternalId}");
loyalty.Entry(customer).CurrentValues.SetValues(updateCustomer);
loyalty.Entry(customer).State = EntityState.Modified;
Console.WriteLine($"customer last name: {customer.LastName}");
loyalty.SaveChanges();
//TODO expand code to cover scenarios such as an additional address on an udpate
}
}
catch (ArgumentNullException e)
{
Console.WriteLine(e);
throw new CustomerNotFoundException();
}
catch (Exception ex)
{
Console.WriteLine($"{ex}");
}
}
}