forked from ddrilling/AsbCloudServer
Merge pull request 'bug fixing in UserRepositoty.UpdateAsync' (#23) from Task/8543610 into dev
Reviewed-on: http://test.digitaldrilling.ru:8080/DDrilling/AsbCloudServer/pulls/23
This commit is contained in:
commit
8a42c16993
@ -68,8 +68,6 @@ namespace AsbCloudDb.Model
|
||||
int SaveChanges();
|
||||
int SaveChanges(bool acceptAllChangesOnSuccess);
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
|
||||
DbSet<TEntity> Set<TEntity>(string name) where TEntity : class;
|
||||
DbSet<TEntity> Set<TEntity>() where TEntity : class;
|
||||
|
||||
}
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
using AsbCloudApp.Data;
|
||||
using AsbCloudApp.Exceptions;
|
||||
using AsbCloudApp.Repositories;
|
||||
using AsbCloudDb;
|
||||
using AsbCloudDb.Model;
|
||||
using AsbCloudInfrastructure.EfCache;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
@ -11,6 +9,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace AsbCloudInfrastructure.Repository
|
||||
{
|
||||
@ -29,10 +28,12 @@ namespace AsbCloudInfrastructure.Repository
|
||||
dst => dst.Files,
|
||||
dst => dst.RelationUsersUserRoles)
|
||||
.Config;
|
||||
|
||||
public UserRepository(IAsbCloudDbContext dbContext, IUserRoleRepository userRoleRepository) {
|
||||
private readonly IMemoryCache memoryCache;
|
||||
public UserRepository(IAsbCloudDbContext dbContext, IUserRoleRepository userRoleRepository, IMemoryCache memoryCache)
|
||||
{
|
||||
this.dbContext = dbContext;
|
||||
this.userRoleRepository = userRoleRepository;
|
||||
this.memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
public async Task<int> InsertAsync(UserExtendedDto dto, CancellationToken token)
|
||||
@ -58,31 +59,36 @@ namespace AsbCloudInfrastructure.Repository
|
||||
|
||||
public async Task<IEnumerable<UserExtendedDto>> GetAllAsync(CancellationToken token)
|
||||
{
|
||||
var dtos = (await GetCacheUserAsync(token)).ToList();
|
||||
if (dtos is null)
|
||||
var users = await GetCacheUserAsync(token);
|
||||
if (users is null)
|
||||
return Enumerable.Empty<UserExtendedDto>();
|
||||
|
||||
for (var i = 0; i < dtos.Count; i++)
|
||||
dtos[i].RoleNames = GetRolesNamesByIdUser(dtos[i].Id);
|
||||
var dtos = new List<UserExtendedDto>();
|
||||
foreach(var user in users)
|
||||
{
|
||||
var dto = Convert(user);
|
||||
dto.RoleNames = GetRolesNamesByIdUser(user.Id);
|
||||
dtos.Add(dto);
|
||||
};
|
||||
return dtos;
|
||||
}
|
||||
|
||||
|
||||
public UserExtendedDto? GetOrDefault(int id)
|
||||
{
|
||||
var dto = GetCacheUser().FirstOrDefault(u => u.Id == id);
|
||||
if (dto is null)
|
||||
var user = GetCacheUser().FirstOrDefault(u => u.Id == id);
|
||||
if (user is null)
|
||||
return null;
|
||||
var entity = Convert(dto);
|
||||
var dto = Convert(user);
|
||||
dto.RoleNames = GetRolesNamesByIdUser(dto.Id);
|
||||
return dto;
|
||||
}
|
||||
|
||||
public async Task<UserExtendedDto?> GetOrDefaultAsync(int id, CancellationToken token)
|
||||
{
|
||||
var dto = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
|
||||
if (dto is null)
|
||||
var user = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
|
||||
if (user is null)
|
||||
return null;
|
||||
|
||||
var dto = Convert(user);
|
||||
dto.RoleNames = GetRolesNamesByIdUser(dto.Id);
|
||||
return dto;
|
||||
}
|
||||
@ -90,11 +96,13 @@ namespace AsbCloudInfrastructure.Repository
|
||||
public async Task<int> UpdateAsync(UserExtendedDto dto, CancellationToken token)
|
||||
{
|
||||
if (dto.Id <= 1)
|
||||
throw new ArgumentInvalidException($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
|
||||
|
||||
var oldUser = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == dto.Id);
|
||||
if (oldUser is null)
|
||||
return 0;
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
|
||||
|
||||
if (oldUser.Login != dto.Login)
|
||||
await AssertLoginIsBusyAsync(dto.Login, token);
|
||||
@ -102,26 +110,44 @@ namespace AsbCloudInfrastructure.Repository
|
||||
var userRoles = await userRoleRepository.GetByNamesAsync(dto.RoleNames, token).ConfigureAwait(false);
|
||||
await UpdateRolesCacheForUserAsync(dto.Id, userRoles, token);
|
||||
|
||||
var entity = Convert(dto);
|
||||
|
||||
var result = dbContext.Users.Upsert(entity);
|
||||
var entity = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id);
|
||||
if (entity is null)
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
|
||||
entity.Id = dto.Id;
|
||||
entity.Login = dto.Login;
|
||||
entity.Name = dto.Name;
|
||||
entity.Email = dto.Email;
|
||||
entity.Phone = dto.Phone;
|
||||
entity.Surname = dto.Surname;
|
||||
entity.Patronymic = dto.Patronymic;
|
||||
entity.Position = dto.Position;
|
||||
entity.IdCompany = dto.IdCompany;
|
||||
entity.IdState = dto.IdState;
|
||||
await dbContext.SaveChangesAsync(token);
|
||||
DropCacheUsers();
|
||||
return result.Entity.Id;
|
||||
return entity.Id;
|
||||
}
|
||||
|
||||
public async Task<int> DeleteAsync(int id, CancellationToken token)
|
||||
{
|
||||
var dto = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
|
||||
if (dto is null)
|
||||
return 0;
|
||||
|
||||
var entity = Convert(dto);
|
||||
var result = dbContext.Users.Remove(entity);
|
||||
var user = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
|
||||
if (user is null)
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {id}. You can't edit this user.", nameof(id));
|
||||
var query = dbContext
|
||||
.Users
|
||||
.Where(u => u.Id == id);
|
||||
if (query.Any())
|
||||
{
|
||||
var result = dbContext.Users.Remove(query.First());
|
||||
await dbContext.SaveChangesAsync(token);
|
||||
DropCacheUsers();
|
||||
return result.Entity.Id;
|
||||
}
|
||||
throw new ArgumentInvalidException
|
||||
($"Invalid id {id}. You can't edit this user.", nameof(id));
|
||||
}
|
||||
|
||||
public IEnumerable<UserRoleDto> GetRolesByIdUser(int idUser, int nestedLevel = 0)
|
||||
{
|
||||
@ -156,9 +182,14 @@ namespace AsbCloudInfrastructure.Repository
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetRolesNamesByIdUser(int idUser)
|
||||
=> GetRolesByIdUser(idUser, 7)
|
||||
{
|
||||
var userRoles = GetRolesByIdUser(idUser, 7)
|
||||
.Select(r => r.Caption)
|
||||
.Distinct();
|
||||
if (userRoles.Any())
|
||||
return userRoles;
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
private async Task AssertLoginIsBusyAsync(string login, CancellationToken token)
|
||||
{
|
||||
@ -169,56 +200,80 @@ namespace AsbCloudInfrastructure.Repository
|
||||
throw new ArgumentInvalidException($"Login {login} is busy by {existingUserDto.MakeDisplayName()}, id{existingUserDto.Id}", nameof(login));
|
||||
}
|
||||
|
||||
private Task<IEnumerable<UserExtendedDto>> GetCacheUserAsync(CancellationToken token)
|
||||
=> dbContext.Users
|
||||
.Include(r => r.Company)
|
||||
.Include(r => r.RelationUsersUserRoles)
|
||||
.FromCacheAsync(userCacheTag, cacheObsolence, Convert, token);
|
||||
private IEnumerable<UserExtendedDto> GetCacheUser()
|
||||
=> dbContext.Users
|
||||
.Include(r => r.Company)
|
||||
.Include(r => r.RelationUsersUserRoles)
|
||||
.FromCache(userCacheTag, cacheObsolence, Convert);
|
||||
private void DropCacheUsers()
|
||||
=> dbContext.Users.DropCache(userCacheTag);
|
||||
|
||||
private Task<IEnumerable<RelationUserUserRole>> GetCacheRelationUserUserRoleAsync(CancellationToken token)
|
||||
=> dbContext.RelationUserUserRoles
|
||||
.Include(r => r.UserRole)
|
||||
.Include(r => r.User)
|
||||
.FromCacheAsync(relationUserUserRoleCacheTag, cacheObsolence, token);
|
||||
private IEnumerable<RelationUserUserRole> GetCachRelationUserUserRoleCacheTag()
|
||||
=> dbContext.RelationUserUserRoles
|
||||
.Include(r => r.UserRole)
|
||||
.Include(r => r.User)
|
||||
.FromCache(relationUserUserRoleCacheTag, cacheObsolence);
|
||||
private void DropCacheRelationUserUserRoleCacheTag()
|
||||
=> dbContext.RelationUserUserRoles.DropCache(relationUserUserRoleCacheTag);
|
||||
|
||||
private async Task UpdateRolesCacheForUserAsync(int idUser, IEnumerable<UserRoleDto> newRoles, CancellationToken token)
|
||||
{
|
||||
var relations = (await GetCacheRelationUserUserRoleAsync(token)).Where(r => r.IdUser == idUser);
|
||||
dbContext.RelationUserUserRoles.RemoveRange(relations);
|
||||
var cache = memoryCache.GetOrCreate(relationUserUserRoleCacheTag, cacheEntry =>
|
||||
{
|
||||
cacheEntry.AbsoluteExpirationRelativeToNow = cacheObsolence;
|
||||
cacheEntry.SlidingExpiration = cacheObsolence;
|
||||
var query = dbContext.RelationUserUserRoles
|
||||
.Include(r => r.UserRole)
|
||||
.Include(r => r.User);
|
||||
var entities = query.ToArray();
|
||||
return entities;
|
||||
});
|
||||
return cache!;
|
||||
}
|
||||
private void DropCacheRelationUserUserRoleCacheTag()
|
||||
{
|
||||
memoryCache.Remove(relationUserUserRoleCacheTag);
|
||||
}
|
||||
|
||||
if (newRoles?.Any() == true)
|
||||
await dbContext.RelationUserUserRoles.AddRangeAsync(newRoles.Select(role => new RelationUserUserRole
|
||||
private async Task UpdateRolesCacheForUserAsync(int idUser, IEnumerable<UserRoleDto> roleDtos, CancellationToken token)
|
||||
{
|
||||
var relations = dbContext.RelationUserUserRoles.Where(r => r.IdUser == idUser);
|
||||
dbContext.RelationUserUserRoles.RemoveRange(relations);
|
||||
var entityRoles = roleDtos.Select(role => new RelationUserUserRole
|
||||
{
|
||||
IdUser = idUser,
|
||||
IdUserRole = role.Id
|
||||
}), token).ConfigureAwait(false);
|
||||
|
||||
});
|
||||
dbContext.RelationUserUserRoles.AddRange(entityRoles);
|
||||
await dbContext.SaveChangesAsync(token);
|
||||
DropCacheRelationUserUserRoleCacheTag();
|
||||
}
|
||||
|
||||
protected virtual User Convert(UserExtendedDto dto)
|
||||
private void DropCacheUsers()
|
||||
=> memoryCache.Remove(userCacheTag);
|
||||
|
||||
private IEnumerable<User> GetCacheUser()
|
||||
{
|
||||
var cache = memoryCache.GetOrCreate(userCacheTag, cacheEntry =>
|
||||
{
|
||||
cacheEntry.AbsoluteExpirationRelativeToNow = cacheObsolence;
|
||||
cacheEntry.SlidingExpiration = cacheObsolence;
|
||||
var query = dbContext.Users
|
||||
.Include(r => r.Company)
|
||||
.Include(r => r.RelationUsersUserRoles);
|
||||
var entities = query.ToArray();
|
||||
return entities;
|
||||
});
|
||||
return cache!;
|
||||
}
|
||||
|
||||
private Task<IEnumerable<User>> GetCacheUserAsync(CancellationToken token)
|
||||
{
|
||||
var cache = memoryCache.GetOrCreateAsync(userCacheTag, async (cacheEntry) =>
|
||||
{
|
||||
cacheEntry.AbsoluteExpirationRelativeToNow = cacheObsolence;
|
||||
cacheEntry.SlidingExpiration = cacheObsolence;
|
||||
var query = dbContext.Users
|
||||
.Include(r => r.Company)
|
||||
.Include(r => r.RelationUsersUserRoles);
|
||||
var entities = await query.ToArrayAsync(token);
|
||||
return entities.AsEnumerable();
|
||||
});
|
||||
return cache!;
|
||||
}
|
||||
|
||||
protected User Convert(UserExtendedDto dto)
|
||||
{
|
||||
var entity = dto.Adapt<User>(userTypeAdapterConfig);
|
||||
if (string.IsNullOrEmpty(entity.PasswordHash))
|
||||
entity.PasswordHash = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id)?.PasswordHash;
|
||||
return entity;
|
||||
}
|
||||
|
||||
protected virtual UserExtendedDto Convert(User entity)
|
||||
{
|
||||
var dto = entity.Adapt<UserExtendedDto>();
|
||||
|
Loading…
Reference in New Issue
Block a user