Set Id field when inserting using entity framework

Viewed 1343

I get error when trying to insert entity, (whole graph to be correct) using Entity framework when Id is has some set value, for example 6. It has it because it was stored in another database, and I can manually set it for each element in a list, and for each element in sublist etc etc. But I have to do this for each element, and for each query. I would like to have unique global way of setting Id field to zero because when I try to insert value I get error:

Cannot insert explicit value for identity column in table 'XXX' when IDENTITY_INSERT is set to OFF.

I want my database to set Ids, and make entity framework to ignore if Id is set to anything besides 0

What I tried was to ovveride OnSaveChanges and that seems to late because when Add or AddRange method is used object was started to being tracked and I cannot set Id to multiple objects in a list.

1 Answers

In EF Core 3.x you can handle ChangeTracker.Tracked event and reset explicitly set autogenerated PK for each Added entity like this (it doesn't need to be outside, you can self attach the db context to that event):


dbContext.ChangeTracker.Tracked += (sender, e) =>
{
    if (!e.FromQuery && e.Entry.State == EntityState.Added && e.Entry.IsKeySet)
    {
        var pk = e.Entry.Metadata.FindPrimaryKey();
        if (pk.Properties.Count == 1)
        {
            var pkProperty = pk.Properties[0];
            if (pkProperty.ValueGenerated == ValueGenerated.OnAdd &&
                defaultValues.TryGetValue(pkProperty.ClrType, out var defaultValue))
            {
                e.Entry.State = EntityState.Detached;
                e.Entry.CurrentValues[pkProperty] = defaultValue;
                var newEntry = e.Entry.Context.Entry(e.Entry.Entity);
                newEntry.State = EntityState.Added;
            }
        }
    }
};

where defaultValues is a dictionary with boxed 0 (zero) values of the supported auto-increment property types (you can add more if needed):

static readonly Dictionary<Type, object> defaultValues = new Dictionary<Type, object>
{
    { typeof(int), default(int) },
    { typeof(long), default(long) },
    { typeof(decimal), default(decimal) },
};

But note that this won't fix relationships which use explicit FK properties without reference navigation property.

Related