0

I am using Entity Framework 6 Code First. I have two Entities:

public class User
{
    [Key]
    public Guid Id { get; set; }

    public string Name { get; set; }

    public string Mail { get; set; }

    public DateTime PwLastSet { get; set; }

    public virtual ICollection<Group> Groups { get; set; }
}

and

public class Group
{
    [Key]
    public Guid Id { get; set; }

    public string Name { get; set; }

    public string Description{ get; set; }

    public int GroupType { get; set; }

    public virtual ICollection<User> Members { get; set; }
}

in a many-to-many relationship and a joining entity GroupUsers which is generated automatically by EFCore and only includes the two Key properties from the original entities which make the primary key as well as foreign keys from the two base Entities. All this is fine and the database objects including the joining table have been created in the migration with no issues.

The problem starts when trying to Insert data into either of the two tables using EFCore.

private async Task SynchronizeUsersAsync()
{
    var localUsers = await _userRepo.ListAllAsync();
    List<User> remoteUsers = _usersHelper.GetUsers();

    var toAdd = new List<User>();
    foreach (var remoteUser in remoteUsers)
    {
        var localUser = localUsers.FirstOrDefault(x => x.Id.Equals(remoteUser.Id));
        if (localUser == null)
        {
            toAdd.Add(remoteUser);
        }
        else if (!localUser.Equals(remoteUser))
        {
            _mapper.Map(remoteUser, localUser);
        }
    }

    await DbContext.Set<User>().AddRangeAsync(toAdd);
    await DbContext.SaveChangesAsync();

    //delete is irrelevant at the moment

}

I get an exception:

System.InvalidOperationException: The instance of entity type 'Group' 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.

As every User potentially belongs to multiple Groups this is also supposed to insert a new row into the joining table GroupUsers for every object in ICollection<Group> Groups of a User.

I have also tried replacing .AddRangeAsync() with .AddAsync() to Insert on every new User which ended up with the same exception.

Brutlex
  • 1
  • 2
  • Have you debug to check which step cause this error? I try your code in my project, It will not report this error. Maybe you can refer to this [issue](https://stackoverflow.com/questions/36856073/the-instance-of-entity-type-cannot-be-tracked-because-another-instance-of-this-t). – Xinran Shen Jan 04 '23 at 08:13

1 Answers1

0

The problem occurs because of _mapper.Map. When it copies the Groups collection, it also copies every Group inside of it instead of using the same reference. This way you add different group objects to the DbContext, but they have the same Id.

The solution would be to create a mapper configuration for Groups field to make a shallow copy instead of a deep copy. In other words copy the reference to the collection (or create a new collection, but copy the references of the objects without copying them). You should probably do the same for Users field in the Group class.

theemee
  • 769
  • 2
  • 10
  • Hi, thanks for the help! Even though this seemed like it could be the issue, the Exception still happens on the first run while the table is empty. This means the code part where the mapping occurs is never reached. I also practically tested this to confirm. – Brutlex Jan 03 '23 at 14:14
  • @Brutlex well, as far as I understand, the "remote" users are not in your database, but do they have empty groups collection? If not, then it could still be an issue that you add two different objects with same ids to the DbContext – theemee Jan 03 '23 at 14:24