Entity Framework Error - Entity Type Cannot be Tracked

January 01, 2023

Entity Framework has a few quirks which, if you’re used to using something like ADO.Net, may be a little confusing. One such quirk is its unwavering belief that it must own all of the data that you’re inserting or updating. If you try to update or insert a record, and it has a different opinion of the state of that data, you’ll get an error like this:

System.InvalidOperationException: ‘The instance of entity type ‘SomeData’ cannot be tracked because another instance with the same key value for {‘Id’} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using ‘DbContextOptionsBuilder.EnableSensitiveDataLogging’ to see the conflicting key values.’

In this post, I’m going to go through this error, and some possible ways to mitigate. Let’s start with debugging.

EnableSensitiveDataLogging

The first thing to consider is in the error message itself. Unless this option is enabled, EF will not output any data in the error message; enabling this is quite easy, but you should think carefully before you leave this running in a production environment.

services.AddDbContext<MyDbContext>(a =>
{
    a.UseSqlServer(connectionString);
    a.EnableSensitiveDataLogging();
});

This will give you a small amount of additional information; that is, it’ll tell you what the specific conflicting record is. This may help. but typically, this will be a complex update and the issue may simply be that EF knows that the record exists, but doesn’t believe that you should.

Read the Record

One easy fix here is to simply read the record first. In terms of code, this is a very simple change; something like the following:

var myData = _myDbContext.SomeData.SingleOrDefault(a => a.Id == newId);    

SomeData newData = new()
{
    Data1 = myData ?? otherValue,
    . . .
};

var result = _myDbContext.SomeData.Add(newData);

If you track the query, it’s clever enough to not go off to the DB twice (unless you call something like a .ToList() on it), so the whole thing is just a single DB call.



Profile picture

A blog about one man's journey through code… and some pictures of the Peak District
Twitter

© Paul Michaels 2024