iMapster's issues with identity in .NET

46 views Asked by At

I want to map a DTO with the identity model (entity).

But I get the following error

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

The code I have written:

 public static TypeAdapterConfig MapUserToUpdateUserDto()
 {
     var config = new TypeAdapterConfig();
     config.NewConfig<IdentityUser,UpdateUserDto>()
         .Map(e => e.PhoneNumber, d => d.PhoneNumber)
         .Map(e => e.Email, d => d.Email)
         .Map(e => e.UserName, d => d.UserName)
         .Map(e => e.Active, d => d.EmailConfirmed)
         .Map(e => e.Active, d => d.PhoneNumberConfirmed)
         .TwoWays();
     return config;
 }

 public async Task UpdateUser(UpdateUserDto model)
 {
     var user = await _userManager.FindByIdAsync(model.Id!);
     user = model.Adapt<IdentityUser>(UserMapster.MapUserToUpdateUserDto());
     
     var resultUpdateUser= await _userManager.UpdateAsync(user);

     if (resultUpdateUser.Succeeded)
     {
         if (!string.IsNullOrEmpty(model.Password) && !string.IsNullOrEmpty(model.PasswordConfirmed))
         {
             var token = await _userManager.GeneratePasswordResetTokenAsync(user);
             await _userManager.ResetPasswordAsync(user, token, model.Password);
         }

         var roles = await _userManager.GetRolesAsync(user!);

         await _userManager.RemoveFromRolesAsync(user, roles);
         await _userManager.AddToRolesAsync(user, model.Role!);
     }
 }

Thank you for helping me

2

There are 2 answers

1
movahedijam On BEST ANSWER

Thank you, I changed my code to this and my problem was solved

 public async Task UpdateUser(UpdateUserDto model)
 {
     var user = await _userManager.FindByIdAsync(model.Id!);
     model.Adapt(user, UserMapster.MapUserToUpdateUserDto());
     var resultUpdateUser = await _userManager.UpdateAsync(user!);
     if (resultUpdateUser.Succeeded)
     {
         if (!string.IsNullOrEmpty(model.Password) && !string.IsNullOrEmpty(model.PasswordConfirmed))
         {
             var token = await _userManager.GeneratePasswordResetTokenAsync(user);
             await _userManager.ResetPasswordAsync(user, token, model.Password);
         }

         var roles = await _userManager.GetRolesAsync(user!);

         await _userManager.RemoveFromRolesAsync(user, roles);
         await _userManager.AddToRolesAsync(user, model.Role!);
     }
 }

0
Jason Pan On

Change your UpdateUser method like below.

Adapt the changes onto user, not replacing it.

 public async Task UpdateUser(UpdateUserDto model)
 {
     var user = await _userManager.FindByIdAsync(model.Id!);
     // Change your code here
     // adapt the changes onto it, not replacing the `user` 
     model.Adapt<IdentityUser>(UserMapster.MapUserToUpdateUserDto());
     
     var resultUpdateUser= await _userManager.UpdateAsync(user);

     if (resultUpdateUser.Succeeded)
     {
         if (!string.IsNullOrEmpty(model.Password) && !string.IsNullOrEmpty(model.PasswordConfirmed))
         {
             var token = await _userManager.GeneratePasswordResetTokenAsync(user);
             await _userManager.ResetPasswordAsync(user, token, model.Password);
         }

         var roles = await _userManager.GetRolesAsync(user!);

         await _userManager.RemoveFromRolesAsync(user, roles);
         await _userManager.AddToRolesAsync(user, model.Role!);
     }
 }