I've got an object that has a key stored as a GUID as well as a friendlyID, like this:
public class Job {
[Key]
public Guid Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int FriendlyId { get; set; }
public string Description { get; set; }
}
However when I try to update description using my update method:
public void Update(Job job, Job jobParam) {
if (job == null) {
throw new AppException("Job does not exist");
}
//Update job properties
job.Description = jobParam.Description;
_context.Job.Update(job);
_context.SaveChanges();
}
I get an error stating:
System.Data.SqlClient.SqlException: Cannot update identity column 'FriendlyId'
I've made sure that the correct object is trying to be updated, but I can't understand why friendlyID would try to get updated when it has not been changed. When looking online I can see that there was a bug in EF core 1.1 that would cause this issue to occur, but nothing about 2.0 or about a value that isn't a key.
The exact behavior of the generated properties in EF Core is still in a process of tweaking. EF Core 2.0 introduced two new property metadata properties - BeforeSaveBehavior
and AfterSaveBehavior
. There is no data annotation/fluent API for setting them and by default they are implied from value generating strategy and whether the property is part of the key. At the same time they affect the behavior of the tracking operations.
The problem here is that for identity columns (i.e. ValueGeneratedOnAdd
) which are not part of a key, the AfterSaveBehavior
is Save
, which in turn makes Update
method to mark them as modified, which in turn generates wrong UPDATE
command.
To fix that, you have to set the AfterSaveBehavior
like this (inside OnModelCreating
override):
modelBuilder.Entity<Job>()
.Property(e => e.FriendlyId)
.ValueGeneratedOnAdd()
.Metadata.AfterSaveBehavior = PropertySaveBehavior.Throw; // <--
Update: In EF Core 3.0+ many metadata properties have been replaced with Get/Set
methods, so just use the corresponding method:
.Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Throw);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With