I am migrating an ASP.NET Core 2.2 application using EF Core 2.2 to ASP.NET Core 3.0 anf EF Core 3.0.
On one particular method, the back-end receives a DTO from the front-end and, using Automapper, converts it to the equivalent entity type, attaches it to the DbContext, and saves. This works perfectly on EF Core 2.2, but fails with the following message on EF Core 3.0:
The instance of entity type 'ServiceProvider' cannot be tracked because another
instance with the same key value for {'Id'} is already being tracked
This is the code in question:
var sqresponse = _mapper.Map<SurveyQuestionResponse>(sqresponseDTO);
_context.Attach(sqresponse); // <=== Throws exception
_context.SaveChanges();
And here are the entities with the relevant classes:
public class SurveyQuestionResponse
{
public int? Id { get; set; }
public List<Answer> Answers { get; set; } = new List<Answer>();
}
public class Answer
{
public int? Id { get; set; }
public int SurveyQuestionResponseId { get; set; }
public ServiceProvider ServiceProvider { get; set; }
}
The data passed to that method from the front-end has two Answer
, both of them containing a ServiceProvider
with Id = 56
.
{
answers: [
{
// some more properties here
serviceProviderId: 56,
serviceProvider: { id: 56, name: "Foo" },
},
{
// some more properties here
serviceProviderId: 56,
serviceProvider: { id: 56, name: "Foo" },
}
]
}
These two ServiceProvider
entities are meant to exist in the database; I need both Answer
in this case associated with the existing ServiceProvider
entity with {Id: 56}
This seems to be a problem for EntityFramework Core 3.0, but was perfectly fine for EF Core 2.2.
I suspect this has to do with this breaking change: DetectChanges honors store-generated key values, but I think the proposed Mitigation would fix this particular problem, but create another one when trying to insert a new ServiceProvider
entity. Am I correct?
How can this be made to work with EF Core 3.0?
I ended up solving it by making sure only answer.ServiceProviderId
is filled in, and answer.ServiceProvider
is null
when attaching.
The JSON being passed to the backend now looks like this, then:
{
answers: [
{
// some more properties here
serviceProviderId: 56,
serviceProvider: null,
},
{
// some more properties here
serviceProviderId: 56,
serviceProvider: null,
}
]
}
With this, the calls to _context.Attach(...)
and _context.SaveChanges()
work without problems.