-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to cache entities in memory and attach them correctly - avoid identity resolution issue #24697
Comments
Perhaps an even more understandable reproduction is the following annotated code: using (var db = new TestDbContext()) {
// here we attach the cached entities (would love to attach them on a per-need basis, not always)
db.AttachRange(statesCache);
// here we query an entity which includes related State entity, but since it was attached before, object instances are
// NOT replaced
var person = db.People
.Include(x => x.AssignedStates)
.ThenInclude(x => x.State)
.OrderBy(x => x.Id).First();
Console.WriteLine($"Person: {person.Name}");
Console.WriteLine($"Assigned states: {person.AssignedStates.Count}");
foreach(var assignedState in person.AssignedStates) {
Console.WriteLine($" {assignedState.State.Name}");
}
// here we are intentionally using a new object instance (with the same key ("VIC")), to reproduce the error
person.AssignedStates = new List<PersonState> { new PersonState { Person = person, State = new State("VIC", "Victoria")}};
db.SaveChanges();
} I would expect, that since the entity |
No, this isn't currently possible. Please vote for Provide a hook for identity resolution. The challenge with doing this automatically is how to deal with differences in the two graphs, in particular when it comes to navigations. |
Thank you @ajcvickers. I figured as much. So, basically, the only approach to caching is to eagerly attach them to the DbContext. |
Ask a question
I am looking for a guidance on how to cache entities and attach them correctly to the
DbContext
so that they will play along with the queries that load the "same" entities.I encountered an issue when caching the results of EF core query and reusing those results in an update scenario. The issue was that EF Core complained with an exception:
That exception is due to the fact that the states were loaded by a query similar to
person.Include(p => p.States).ToListAsync()
, but when updating a list of states assigned to a "person", instances from cache were used.In order to avoid this issue, one can attach the cached entities to the
DbContext
before querying a person with related entities, but it is cumbersome.The reason for this behaviour is clearly explained in the documentation - Identity resolution and queries (emphasis mine):
Issue reproduction
I've prepared a simple repro of the issue below, where you can see, that if the cached entities are attached after the query has been performed, then the update will fail with the above exception. The workaround is to attach early in the DbContext initialization, but this is impractical, if done within a "repository", because the cached entities are not "centralized".
So, the question is: is there a way, to cache the entities and attach them "whenever" and make it work? Or do they need to be attached before any of the entities are loaded in order to avoid the documented behaviour? In other words, EF Core uses reference equality when comparing tracked objects, but relies on primary key value to decide which entity to track (e.g. when loading from DB, it skips tracking the loaded entity if another entity with the same primary key value is already tracked).
Reproduction:
Reproduction code
EF Core version info
EF Core version: 5.0.5
Database provider: Microsoft.EntityFrameworkCore.SqlServer)
Target framework: .NET 5.0
Operating system: MacOS
The text was updated successfully, but these errors were encountered: