2

For example, there are the following classes:

public class Detail
{
    public int Id { get; set; }
    public int MachineId { get;set; }
    public Machine Machine { get; set; }
}

public class Machine
{
    public int Id { get; set; }
    public ICollection<Detail> Details { get; set; }
}

And here is a current state:

  • Machine1
    • Detail1
  • Machine2
    • Detail2

And I just want to move Detail2 from Machine2 to Machine1. Try it:

var machine1 = myDbContext.Machines
    .Include(m => m.Details)
    .First(m => m.Id == 1);

var machine2 = myDbContext.Machines
    .Include(m => m.Details)
    .First(m => m.Id == 2);

var detail2 = machine2.Details.First(d => d.Id == 2); // It still works fine

machine2.Details.Remove(detail2);
machine1.Details.Add(detail2);

myDbContext.SaveChanges(); // Exception!

System.InvalidOperationException: The instance of entity type 'MyNamespace.Detail' cannot be tracked because another instance of this type with the same key is already being tracked. For new entities consider using an IIdentityGenerator to generate unique key values.

It seems like a bug!

Or am I doing something wrong?

hcp
  • 3,268
  • 6
  • 26
  • 41

1 Answers1

0

Tested with Entity Framework Core 3.1.5

Once an item is removed from a collection it seems that it is always deleted even if added to another one (in any order add/remove or remove/add).

What works is to add the item to the second collection but without removing it from the first collection. What's is interesting is that after a call to SaveChanges the in memory collections are updated: the item is removed from the first collection by EF.

var machine1 = myDbContext.Machines
    .Include(m => m.Details)
    .First(m => m.Id == 1);

var machine2 = myDbContext.Machines
    .Include(m => m.Details)
    .First(m => m.Id == 2);

var detail2 = machine2.Details.First(d => d.Id == 2); // It still works fine

machine1.Details.Add(detail2);

myDbContext.SaveChanges();

Assert.Contains(detail2, machine1.Details);
Assert.DoesNotContain(detail2, machine2.Details);

You can then check on the database that the foreign key has changed or retrieving the entities on a new DbContext.

It is interesting that the in memory collections are updated after the SaveChanges, if a transaction is wrapping this code you can continue using the in memory entities safely which are updated.

polkduran
  • 2,533
  • 24
  • 34