2

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.

2
  • Can you set the Id to 0 in the business logic before adding it to any Entity Framework collection/tracking? It sounds like you're getting the object from another system which already has an identifier and need to strip out that identifier, which I would interpret as the business logic of the mapping between the two systems. Commented Jun 16, 2020 at 11:48
  • Ofcourse, but I have to foreach each element in a list and if each element has sublist I have to foreach that sublist. And if each element of sublist has some complex object I have to set it. Also I have to do this in each query, in lot of places. It does not make sense to do that but to find way to do it "globally" Commented Jun 16, 2020 at 11:50

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

I will try that but it seems it would work. Can you please also look at this issue: stackoverflow.com/questions/62425113/…
Unfortunattely, when I try to insert another object and it happens to have Id 1, but in context is already some another which has Id=1 I get error: zhe instance of entity type 'Vehicle' cannot be tracked because another instance with the key value '{Id: 1}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Before I get chance to clear that value to zero
Yeah, unfortunately this doesn't work with mixing AddNew with other other CRUD. There is no extension point before tracking.
Yes, but I can disable tracking using AsNoTracking when using this mix. Did you have chance to take a look at this interesting problem: stackoverflow.com/questions/62425113/…
Not yet, will when have some time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.