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

时间:2019-08-07 15:45:56

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

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

  

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

关于上述错误,互联网上存在多个问题,但是在通过UserManager更新用户时没有一个问题。

这是我的代码:

服务配置:

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

UserEntity:

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

剃刀页面处理程序:

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

UserBusiness:

    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.Users设置了GetUserByIdAsync();但仍然无法正常工作,并继续引发相同的错误。我做错了吗?请协助解决需要纠正的问题以及我要去哪里。

谢谢。

1 个答案:

答案 0 :(得分:2)

经过一些分析,找出了问题所在。这是因为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
                });
            }
        }

用户业务:

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