Closed mm-ryo closed 2 years ago
I seem to be getting this all over the place lately ... Did something change recently to cause this to happen more often?
I've also noticed if I post an array of something to the api that then gets an entity from the db and makes changes to it more than once EF gets all confused about what's needed rough steps to produce the issue ...
I get this error ^
@robinNode Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.
@TehWardy Please open a new issue and attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.
@robinNode Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.
@TehWardy Please open a new issue and attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.
@ajcvickers I have attached a demo. please take a look at it. thanks a lot. EFCoreTest.zip
@robinNode you seem to be using AutoMapper to map an entity instance to some other type, then map back to the entity type, and then attempting to interact with change tracking using the newly-converted instance. This isn't supported, since there are now two entity instances representing the same thing (i.e. with the same key). If I remove the back-and-forth mapping, everything works fine. Possible solutions are:
context.Entry(original).State = EntityState.Detached;
). Because EF is no longer tracking the original instance, you can now pass it your new, mapped one. However, this is not a recommended technique; while it will work for deleting, for updating it means EF can no longer automatically determine which properties change, so you would have to specify that yourself./cc @ajcvickers this bears some resemblance to the immutable scenario, where the user wants to replace an already-tracked instance with another instance.
@roji Yes, I have been thinking a lot about the immutable scenario, and I think both this and that are dependent on #20124. It's then about conventions and patterns for how resolution happens in that hook. I agree that we should think about these things in a holistic way.
In addition to #20124, maybe some sort of Replace method on the change tracker... Are we tracking something like this already?
I have got this issue and I resolved it with context.ChangeTracker.Clear() with automapper
I have got this issue and I resolved it with context.ChangeTracker.Clear() with automapper
Are you able to supply a sample snippet, I'm also mapping an incoming dto to a dbEntity before saving changes, however I'm doing all the logic within the service layer of the project and don't have direct access to the context but the repository does.
@robinNode
After playing around with your example code, you are indeed asking EF Core to track multiple instances of the same entity.
A simple fix is to do your mapping later on the modified entity:
using (var context = new TestContext())
{
var testEntityModel = context.TestEntity.First();
context.TestEntity.RemoveRange(testEntityModel); // **no exception and table is updated later**
mapper.Map<TestEntity>(testEntityModel); // **removed storage var here just for demo purposes**
context.SaveChanges();
}
Interesting. I'm sure when it comes to how I use EF i'm probably like many, massively abusing it, but I've found that as a testament to how well written it is sometimes just taking an out of the box approach can improve things.
I found that a lot of my problems went away when I instanced up a new context for literally every single row operation on the db. Pooling helped offset the perf hits but on occasion I would get an error from one context where I had somehow attached it to another.
Correct me if i'm wrong but Tracking what entity is attached to what context is certainly not a fun task. I think the bulk of this thread comes down to "EF did a strange thing, something unexpected was tracked on an instance"
Random thought The change tracker: do we really need it at all?
Bear with me on this ... So in my situation I do something like this:
With context pooling and pooled factories this seems to be really fast, (like stupid fast) What does the context give us by having just the one "request scoped" and doing all the work on the one instance that I would lose with this approach?
Another idea I had was to put a thread safety wrapper around a singleton context and just throw out all changes after every transaction with the wrapper but that felt ugly and would likely result in poorer perf since in order to scale i'm using a ton of instances at the moment. but if I could "queue" work to be done on an EF context I could probably make that fairly decent as an approach.
Side quest I noticed that "model caching" / using a single model instance for all contexts doesn't work with query filters. Is this a resolvable problem, I'd really like to take advantage of those gains?
I thought it best to put this in its own ticket ^
Exception details :
The instance of entity type 'Entity' 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.
Steps:
Stack traces
Provider and Version information
EF Core version: Microsoft.EntityFrameworkCore (3.1.7) Database provider: Npgsql.EntityFrameworkCore.PostgreSQL (3.1.4) Target framework: 3.1.7 Operating system: Microsoft Windows 10 Enterprise 64bit IDE: Visual Studio 2019 16.3