-
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
Cannot save changes because same join entity seems to be added multiple times #23339
Comments
|
@xamadev Scratch that, I had the wrong project open. 🤦 |
Note for triage: I am able to reproduce this, but I haven't yet figured out what is going wrong. |
Note for triage: figured out what is going on here. The issue occurs when attaching a graph of entities that includes some join entities referenced not by the many-to-many relationship, but rather by some other relationship on the join entity. If EF encounters the many-to-many relationship first, then it synthesizes a join entity. This then clashes with the entity in the graph when it is found later. The solution to this is probably to move the join entity synthesis to the delayed-fixup stage, at which point we will have encountered all entities in the graph. It might be possible to patch for this, but the change may also be too big/risky to patch. @xamadev A workaround in this case is to make sure that the explicit join entities in the graph are attached first. Something like this: context.AddRange(dataContextDto.Contacts.SelectMany(e => e.Responsibilities));
context.Units.AddRange(dataContextDto.Units);
context.Contacts.AddRange(dataContextDto.Contacts);
context.Elements.AddRange(dataContextDto.Elements);
context.SaveChanges(); |
@ajcvickers Thanks for the workaround! |
@ajcvickers Unfortunately I'm facing same error with the workaround in my production project. I added some new relationships in my reproduction repo:
I added
Stack Trace:
Could you please have a look? |
@xamadev Can you update the code in the reproduction repo with the new model, etc. and I will take a look. I have half an idea for a more general workaround that I can flesh out a bit more with good repro code to test it on. |
@ajcvickers It's already up to date |
@ajcvickers I made a mistake in reproduction repo (is up to date). It's working there but not in production. I'm currently trying to reproduce it |
@ajcvickers Could reproduce the issue, please have a look at my repo. |
@xamadev Try this. The idea is to explicitly add any join entities before adding the other entities. This solution traverses the graph to find them, rather than having to extract them manually from the graph, like the previous solution was attempting to do. private static void PreAddJoinEntities<TEntity>(DbContext context, IEnumerable<TEntity> entities)
{
var tracked = new HashSet<object>();
foreach (var unit in entities)
{
context.ChangeTracker.TrackGraph(unit, 0, n =>
{
var entity = n.Entry.Entity;
if (tracked.Contains(entity))
{
return false;
}
if (entity is UnitToElement
&& n.Entry.State == EntityState.Detached)
{
n.Entry.State = EntityState.Added;
}
tracked.Add(entity);
return true;
});
}
} Used like so: using (var context = GetContextSqlite())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
PreAddJoinEntities(context, dataContextDto.Units);
PreAddJoinEntities(context, dataContextDto.Functions);
PreAddJoinEntities(context, dataContextDto.Groups);
PreAddJoinEntities(context, dataContextDto.Elements);
PreAddJoinEntities(context, dataContextDto.Contacts);
context.Units.AddRange(dataContextDto.Units);
context.Functions.AddRange(dataContextDto.Functions);
context.Groups.AddRange(dataContextDto.Groups);
context.Elements.AddRange(dataContextDto.Elements);
context.Contacts.AddRange(dataContextDto.Contacts);
context.SaveChanges();
} |
@ajcvickers Works fine in reproduction and production project, Thanks for your time! |
Fixes #23339 This stops the change tracker creating a join entity instance for the same join entity that is later discovered in the graph.
Fixes #23339 This stops the change tracker creating a join entity instance for the same join entity that is later discovered in the graph.
Fixes #23339 This stops the change tracker creating a join entity instance for the same join entity that is later discovered in the graph.
Fixes #23339 This stops the change tracker creating a join entity instance for the same join entity that is later discovered in the graph.
I'm buliding a mobile app which syncs it's local SQLite database with a SQL database on a server through a REST API. I'm getting an exception when saving the received data. I set up a small reproduction repo.
My first intention was that JSON.NET creates new objects for the same entity while parsing the json if it occurs multiple times. But JSON.NET does not like described here. Besides the entity UnitToElement with {FK_Element: 2, FK_Unit: 1} occurs only once in the json string.
Stack trace
Include provider and version information
EF Core version: 5.0
Database provider: Microsoft.EntityFrameworkCore.SqlServer ,Microsoft.EntityFrameworkCore.Sqlite
Target framework: .NET Core 3.1
The text was updated successfully, but these errors were encountered: