I got a problem with setting values before saving an added entity. When I don't change the entities values it saves without a problem.
The error I get is this:
SqlException: Cannot insert explicit value for identity column in table 'TableName' when IDENTITY_INSERT is set to OFF.
I am using .net Core 2.1 and my nuget packages are all up to date.
The code below works fine in Entity Framework for the .NET Framework
public override int SaveChanges()
{
try
{
int userId = currentUser.UserId;
IEnumerable<EntityEntry> addedEntities = ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added && e.CurrentValues.ToObject() is ModelBase)
.Select(e => e);
foreach (var e in addedEntities)
{
var clE = e.CurrentValues.ToObject() as ModelBase;
if (clE != null)
{
clE.CreatedOn = DateTime.Now;
clE.CreatedBy = userId;
}
// When I delete this line, it works without a problem
// but it doesn't set the values obviously
e.CurrentValues.SetValues(clE);
}
return base.SaveChanges();
}
catch (Exception dbEx)
{
Exception raise = dbEx;
throw raise;
}
}
Any idea what I am doing wrong?
Thanks Chris
The documentation of ToObject
method states:
Creates an instance of the entity type and sets all its properties using the values from this object.
In other words, the method creates a new entity instance and populates it with the current values of the tracked entity.
Note that at the time you add entity to the context, EF generates temporary values for the identity PK property, so ToObject
copies that value as well.
Then SetValues
copies back all properties of the passed object, including the PK, but now the PK value is marked as persistent (the same will happen if you set explicitly the PK value to some value different than the default 0).
The net effect of all this is that EF will try to insert explicit value into PK key, which normally is disabled (needs special enabling), hence the exception you are getting.
The solution is to not use ToObject
/ SetValues
, but modify the actual tracked entity, which is accessible through Entity
property:
var addedEntities = ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added)
.Select(e => e.Entity)
.OfType<ModelBase>();
foreach (var e in addedEntities)
{
// Here you modify the actual entity instance, so the values
// you set will be considered by the base.SaveChanges() call
e.CreatedOn = DateTime.Now;
e.CreatedBy = userId;
}