无法通过 UserManager<TUser> 在 asp.net core 2.2 应用程序中使用 ef core 2.2 更新用户

fin*_*s10 1 c# repository-pattern asp.net-core-identity asp.net-core-2.2 ef-core-2.2

我正在尝试使用更新用户UserManager<TUser>但收到以下错误

无法跟踪实体类型“UserEntity”的实例,因为已跟踪具有键值“{Id}”的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

互联网上有几个关于上述错误的问题,但在通过UserManager.

这是我的代码:

服务配置:

        services.AddScoped<IUserRepository, UserRepository>();
        services.AddIdentity<UserEntity, UserRoleEntity>()
                    .AddEntityFrameworkStores<GallaContext>()
                    .AddDefaultTokenProviders();
Run Code Online (Sandbox Code Playgroud)

用户实体:

    public class UserEntity : IdentityUser<Guid>
    {
        private ProfileEntity _profile;

        private UserEntity(ILazyLoader lazyLoader)
        {
            LazyLoader = lazyLoader;
        }

        private ILazyLoader LazyLoader { get; set; }

        public UserEntity()
        {

        }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Designation { get; set; }
        public string IdentityNumber { get; set; }
        public bool Active { get; set; }
        public DateTimeOffset CreatedAt { get; set; }
        public string CreatedBy { get; set; }
        public DateTimeOffset? ModifiedAt { get; set; }
        public string ModifiedBy { get; set; }

        public Guid ProfileId { get; set; }
        public ProfileEntity Profile { get => LazyLoader.Load(this, ref _profile); set => _profile = value; }
    }
Run Code Online (Sandbox Code Playgroud)

剃刀页面处理程序:

        public async Task<IActionResult> OnPutAsync(
            [FromForm] UserViewModel userViewModel,
            CancellationToken ct)
        {
            try
            {
                await _user.InitializeAsync(userViewModel.Id, ct);
                var user = _mapper.Map(userViewModel, _user);

                var result = await user.SaveAsync(ct);

                return new JsonResult(new AjaxResultHelper<string>(result.Succeeded)
                {
                    Response = result.ErrorMessage ?? ResponseMessages.DataSaved
                });
            }
            catch (Exception e)
            {
                // Need to log the error

                return new JsonResult(new AjaxResultHelper<string>()
                {
                    Response = e.Message
                });
            }
        }
Run Code Online (Sandbox Code Playgroud)

用户业务:

    public class User : CoreEntityBase
    {
        private readonly IUserRepository _userRepository;
        private readonly IMapper _mapper;

        public User(
            IUserRepository userRepository,
            IMapper mapper)
        {
            _userRepository = userRepository;
            _mapper = mapper;
        }

        public string Name => $"{FirstName} {LastName}";
        public string UserName { get; private set; }
        public string NormalizedUserName { get; private set; }
        public string Email { get; private set; }
        public string NormalizedEmail { get; private set; }
        public bool EmailConfirmed { get; private set; }
        public string PasswordHash { get; private set; }
        public string SecurityStamp { get; private set; }
        public string ConcurrencyStamp { get; private set; }
        public bool LockoutEnabled { get; private set; }

        [Sortable(Default = true)]
        [SearchableString]
        public string FirstName { get; set; }

        [Sortable]
        [SearchableString]
        public string LastName { get; set; }

        [Sortable]
        [SearchableString]
        public string Designation { get; set; }

        [Sortable]
        [SearchableString]
        public string IdentityNumber { get; set; }

        public Guid ProfileId { get; set; }

        [NestedSortable]
        [NestedSearchable]
        public Profile Profile { get; set; }

        public async Task InitializeAsync(
            Guid Id,
            CancellationToken ct)
        {
            if (Id == null)
            {
                throw new ArgumentNullException($"{nameof(Id)} cannot be null");
            }

            var user = await _userRepository.GetUserByIdAsync(Id, ct);
            _mapper.Map(user, this);
            SecurityStamp = user.SecurityStamp;
            UserName = user.UserName;
        }

        public async Task<User> GetUserByIdAsync(
            Guid userId,
            CancellationToken ct)
        {
            var user = await _userRepository.GetUserByIdAsync(userId, ct);

            return _mapper.Map<User>(user);
        }

        public async Task<(bool Succeeded, string ErrorMessage)> SaveAsync(CancellationToken ct)
        {
            if (!Validate())
            {
                return (false, Errors?.First());
            }

            //var userEntity = await _userRepository.GetUserByIdAsync(Id, ct);
            //var userEntity = _mapper.Map(this, userEntity);
            var update = await _userRepository.UpdateUserAsync(this);

            return update;
        }

        public override bool Validate()
        {
            var isValid = true;

            if (string.IsNullOrWhiteSpace(FirstName))
            {
                Errors.Add("FirstName cannot be empty");
                isValid = false;
            }

            if (string.IsNullOrWhiteSpace(LastName))
            {
                Errors.Add("LastName cannot be empty");
                isValid = false;
            }

            if (string.IsNullOrWhiteSpace(Designation))
            {
                Errors.Add("Designation cannot be empty");
                isValid = false;
            }

            return isValid;
        }
    }
Run Code Online (Sandbox Code Playgroud)

用户库:

    public class UserRepository : IUserRepository
    {
        private readonly UserManager<UserEntity> _userManager;
        private readonly IMapper _mapper;

        public UserRepository(
            UserManager<UserEntity> userManager,
            IMapper mapper)
        {
            _userManager = userManager;
            _mapper = mapper;
        }

        public async Task<UserEntity> GetUserByIdAsync(
            Guid userId,
            CancellationToken ct)
        {
            var entity = await _userManager.Users.AsNoTracking().TagWith(nameof(GetUserIdAsync))
                .Include(u => u.Profile)
                .SingleOrDefaultAsync(x => x.Id == userId, ct);

            return entity;
        }

        public async Task<(bool Succeeded, string ErrorMessage)> UpdateUserAsync(User user)
        {
            var userEntity = _mapper.Map<UserEntity>(user);
            var result = await _userManager.UpdateAsync(userEntity);

            if (result.Succeeded)
            {
                return (true, null);
            }

            var firstError = result.Errors.FirstOrDefault()?.Description;
            return (false, firstError);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚我错在哪里。我已经AsNoTracking()设定_userManager.UsersGetUserByIdAsync()方法; 但仍然无法正常工作并不断抛出相同的错误。我做错了吗?请协助说明需要纠正的内容以及我哪里出错了。

提前致谢。

fin*_*s10 5

经过一番分析,找出了问题所在。这是因为GetUserByIdAsync(). 虽然我设置AsNoTracking()_userManager.Users其被EF核心内部跟踪。所以改变了实现以返回用户_userManager.FindByIdAsync并且有效。

这是最终清理的代码。希望这可以帮助某人。

剃刀页面处理程序:

        public async Task<IActionResult> OnPutAsync([FromForm] UserViewModel userViewModel)
        {
            try
            {
                await _user.InitializeAsync(userViewModel.Id);
                var user = _mapper.Map(userViewModel, _user);

                var (Succeeded, ErrorMessage) = await user.SaveAsync();

                return new JsonResult(new AjaxResultHelper<string>(Succeeded)
                {
                    Response = ErrorMessage ?? ResponseMessages.DataSaved
                });
            }
            catch (Exception ex)
            {
                // Need to log the error
                Console.WriteLine(ex.Message);

                return new JsonResult(new AjaxResultHelper<string>()
                {
                    Response = ResponseMessages.DataNotSaved
                });
            }
        }
Run Code Online (Sandbox Code Playgroud)

用户业务:

    public class User : CoreEntityBase
    {
        private readonly IUserRepository _userRepository;
        private readonly IMapper _mapper;

        public User()
        {

        }

        public User(
            IUserRepository userRepository,
            IMapper mapper)
        {
            _userRepository = userRepository;
            _mapper = mapper;
        }

        public string Name { get; set; }

        [Sortable(Default = true)]
        [SearchableString]
        public string FirstName { get; set; }

        [Sortable]
        [SearchableString]
        public string LastName { get; set; }

        [Sortable]
        [SearchableString]
        public string Designation { get; set; }

        [Sortable]
        [SearchableString]
        public string IdentityNumber { get; set; }

        public Guid ProfileId { get; set; }

        [NestedSortable]
        [NestedSearchable]
        public Profile Profile { get; set; }

        public async Task InitializeAsync(Guid Id)
        {
            if (Id == null)
            {
                throw new ArgumentNullException($"{nameof(Id)} cannot be null");
            }

            var userEntity = await _userRepository.GetUserByIdAsync(Id);
            _mapper.Map(userEntity, this);
        }

        public async Task<PagedResults<User>> GetUsersAsync(
            PagingOptions pagingOptions,
            SortOptions<User, UserEntity> sortOptions,
            SearchOptions<User, UserEntity> searchOptions,
            CancellationToken ct)
        {
            var users = await _userRepository.GetUsersAsync(pagingOptions, sortOptions, searchOptions, ct);

            return new PagedResults<User>
            {
                Items = _mapper.Map<User[]>(users.Items),
                TotalSize = users.TotalSize
            };
        }

        public async Task<User> GetUserByIdAsync(Guid userId)
        {
            var userEntity = await _userRepository.GetUserByIdAsync(userId);

            return _mapper.Map<User>(userEntity);
        }

        public async Task<(bool Succeeded, string ErrorMessage)> SaveAsync()
        {
            if (!Validate())
            {
                return (false, Error);
            }

            var userEntity = await _userRepository.GetUserByIdAsync(Id);
            userEntity = _mapper.Map(this, userEntity);
            var update = await _userRepository.UpdateUserAsync(userEntity);

            return update;
        }

        public override bool Validate()
        {
            var isValid = true;

            if (string.IsNullOrWhiteSpace(FirstName))
            {
                Error = "FirstName cannot be empty";
                isValid = false;
            }

            if (string.IsNullOrWhiteSpace(LastName))
            {
                Error = "LastName cannot be empty";
                isValid = false;
            }

            if (string.IsNullOrWhiteSpace(Designation))
            {
                Error = "Designation cannot be empty";
                isValid = false;
            }

            return isValid;
        }
    }
Run Code Online (Sandbox Code Playgroud)

用户存储库:

    public class UserRepository : IUserRepository
    {
        private readonly UserManager<UserEntity> _userManager;

        public UserRepository(
            UserManager<UserEntity> userManager)
        {
            _userManager = userManager;
        }

        public async Task<UserEntity> GetUserByIdAsync(Guid userId)
        {
            var entity = await _userManager.FindByIdAsync(userId.ToString());

            return entity;
        }

        public async Task<(bool Succeeded, string ErrorMessage)> UpdateUserAsync(UserEntity userEntity)
        {
            var result = await _userManager.UpdateAsync(userEntity);

            if (result.Succeeded)
            {
                return (true, null);
            }

            var firstError = result.Errors.FirstOrDefault()?.Description;
            return (false, firstError);
        }
    }
Run Code Online (Sandbox Code Playgroud)