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

标签 c# repository-pattern asp.net-core-2.2 asp.net-core-identity ef-core-2.2

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

The instance of entity type 'UserEntity' cannot be tracked because another instance with the key value '{Id}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

互联网上有几个关于上述错误的问题,但在通过 UserManager 更新用户时没有一个问题.

这是我的代码:

服务配置:

        services.AddScoped<IUserRepository, UserRepository>();
        services.AddIdentity<UserEntity, UserRoleEntity>()
                    .AddEntityFrameworkStores<GallaContext>()
                    .AddDefaultTokenProviders();

用户实体:

    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; }
    }

Razor 页面处理程序:

        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
                });
            }
        }

用户业务:

    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;
        }
    }

用户资料库:

    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);
        }
    }

我不知道我哪里错了。我有AsNoTracking()设置为 _userManager.UsersGetUserByIdAsync()方法;但仍然无法正常工作并继续抛出相同的错误。我做错了吗?请协助指出需要更正的地方以及我哪里出错了。

提前致谢。

最佳答案

经过一些分析找出了问题所在。这是因为 GetUserByIdAsync()。虽然我将 AsNoTracking() 设置为 _userManager.Users,但它在内部由 ef core 跟踪。因此,通过 _userManager.FindByIdAsync 更改了实现以返回用户,并且成功了。

这是最终清理过的代码。希望这对某人有帮助。

Razor 页面处理程序:

        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
                });
            }
        }

用户业务:

    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;
        }
    }

用户存储库:

    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);
        }
    }

关于c# - 无法在 asp.net core 2.2 应用程序中使用 ef core 2.2 通过 UserManager<TUser> 更新用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57398092/

相关文章:

repository-pattern - 当我使用存储库模式时,我应该把业务逻辑放在哪里?

docker 运行时立即退出,错误代码为 139

asp.net-core-2.2 - 防止在 asp.net core 2.2 中重定向到/Account/Login

C# .NET Core 2.2 API 未接收从 Angular 前端发送的参数对象

c# - Java RSA 加密

C# 2.0 设计问题 - 从更大的列表创建子列表

c# - 如何确定哪个 ValidationAttribute 返回了 ModelError

android - RxJava2 Single.Concat 用于存储库模式

orm - 绕过聚合根来编辑单个模型

c# - EqualityComparer<T>.Default 与 T.Equals