Merge pull request #17380 from abpframework/liangshiwei/usercount

Add separate methods to get role and usercount to improve performance
pull/17385/head
maliming 2 years ago committed by GitHub
commit f83abead08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,6 +14,15 @@ public interface IIdentityRoleRepository : IBasicRepository<IdentityRole, Guid>
CancellationToken cancellationToken = default
);
Task<List<IdentityRoleWithUserCount>> GetListWithUserCountAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default
);
Task<List<IdentityRole>> GetListAsync(
string sorting = null,
int maxResultCount = int.MaxValue,

@ -119,11 +119,6 @@ public interface IIdentityUserRepository : IBasicRepository<IdentityUser, Guid>
CancellationToken cancellationToken = default
);
Task<List<RoleWithUserCount>> GetCountAsync(
Guid[] roleIds,
CancellationToken cancellationToken = default
);
Task<IdentityUser> FindByTenantIdAndUserNameAsync(
[NotNull] string userName,
Guid? tenantId,

@ -0,0 +1,16 @@
using System;
namespace Volo.Abp.Identity;
public class IdentityRoleWithUserCount
{
public IdentityRole Role { get; set; }
public long UserCount { get; set; }
public IdentityRoleWithUserCount(IdentityRole role, long userCount)
{
Role = role;
UserCount = userCount;
}
}

@ -1,10 +0,0 @@
using System;
namespace Volo.Abp.Identity;
public class RoleWithUserCount
{
public Guid RoleId { get; set; }
public long UserCount { get; set; }
}

@ -28,6 +28,30 @@ public class EfCoreIdentityRoleRepository : EfCoreRepository<IIdentityDbContext,
.FirstOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, GetCancellationToken(cancellationToken));
}
public virtual async Task<List<IdentityRoleWithUserCount>> GetListWithUserCountAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var roles = await GetListInternalAsync(sorting, maxResultCount, skipCount, filter, includeDetails, cancellationToken: cancellationToken);
var roleIds = roles.Select(x => x.Id).ToList();
var userCount = await (await GetDbContextAsync()).Set<IdentityUserRole>()
.Where(userRole => roleIds.Contains(userRole.RoleId))
.GroupBy(userRole => userRole.RoleId)
.Select(x => new
{
RoleId = x.Key,
Count = x.Count()
})
.ToListAsync(GetCancellationToken(cancellationToken));
return roles.Select(role => new IdentityRoleWithUserCount(role, userCount.FirstOrDefault(x => x.RoleId == role.Id)?.Count ?? 0)).ToList();
}
public virtual async Task<List<IdentityRole>> GetListAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
@ -36,14 +60,7 @@ public class EfCoreIdentityRoleRepository : EfCoreRepository<IIdentityDbContext,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.IncludeDetails(includeDetails)
.WhereIf(!filter.IsNullOrWhiteSpace(),
x => x.Name.Contains(filter) ||
x.NormalizedName.Contains(filter))
.OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(IdentityRole.Name) : sorting)
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
return await GetListInternalAsync(sorting , maxResultCount, skipCount, filter, includeDetails, cancellationToken);
}
public virtual async Task<List<IdentityRole>> GetListAsync(
@ -75,6 +92,24 @@ public class EfCoreIdentityRoleRepository : EfCoreRepository<IIdentityDbContext,
.LongCountAsync(GetCancellationToken(cancellationToken));
}
protected virtual async Task<List<IdentityRole>> GetListInternalAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string filter = null,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.IncludeDetails(includeDetails)
.WhereIf(!filter.IsNullOrWhiteSpace(),
x => x.Name.Contains(filter) ||
x.NormalizedName.Contains(filter))
.OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(IdentityRole.Name) : sorting)
.PageBy(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
[Obsolete("Use WithDetailsAsync")]
public override IQueryable<IdentityRole> WithDetails()
{

@ -263,25 +263,6 @@ public class EfCoreIdentityUserRepository : EfCoreRepository<IIdentityDbContext,
.LongCountAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<RoleWithUserCount>> GetCountAsync(Guid[] roleIds, CancellationToken cancellationToken = default)
{
var users = await (await GetDbSetAsync())
.AsNoTracking()
.Where(user => user.Roles.Any(role => roleIds.Contains(role.RoleId))).IncludeDetails().ToListAsync(GetCancellationToken(cancellationToken));
var result = new List<RoleWithUserCount>();
foreach (var roleId in roleIds)
{
result.Add(new RoleWithUserCount
{
RoleId = roleId,
UserCount = users.Count(t => t.Roles.Any(role => role.RoleId == roleId))
});
}
return result;
}
public virtual async Task<List<OrganizationUnit>> GetOrganizationUnitsAsync(
Guid id,
bool includeDetails = false,

@ -28,7 +28,7 @@ public class MongoIdentityRoleRepository : MongoDbRepository<IAbpIdentityMongoDb
.FirstOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, GetCancellationToken(cancellationToken));
}
public virtual async Task<List<IdentityRole>> GetListAsync(
public virtual async Task<List<IdentityRoleWithUserCount>> GetListWithUserCountAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
@ -36,14 +36,37 @@ public class MongoIdentityRoleRepository : MongoDbRepository<IAbpIdentityMongoDb
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.WhereIf(!filter.IsNullOrWhiteSpace(),
x => x.Name.Contains(filter) ||
x.NormalizedName.Contains(filter))
.OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(IdentityRole.Name) : sorting)
.As<IMongoQueryable<IdentityRole>>()
.PageBy<IdentityRole, IMongoQueryable<IdentityRole>>(skipCount, maxResultCount)
var roles = await GetListInternalAsync(sorting, maxResultCount, skipCount, filter, includeDetails, cancellationToken: cancellationToken);
var roleIds = roles.Select(x => x.Id).ToList();
var userCount = await (await GetMongoQueryableAsync<IdentityUser>(cancellationToken))
.Where(user => user.Roles.Any(role => roleIds.Contains(role.RoleId)))
.SelectMany(user => user.Roles)
.GroupBy(userRole => userRole.RoleId)
.Select(x => new
{
RoleId = x.Key,
Count = x.Count()
})
.ToListAsync(GetCancellationToken(cancellationToken));
return roles.Select(role => new IdentityRoleWithUserCount(role, userCount.FirstOrDefault(x => x.RoleId == role.Id)?.Count ?? 0)).ToList();
}
public virtual async Task<List<IdentityRole>> GetListAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await GetListInternalAsync(
sorting,
maxResultCount,
skipCount,
filter,
includeDetails,
cancellationToken);
}
public virtual async Task<List<IdentityRole>> GetListAsync(
@ -75,4 +98,22 @@ public class MongoIdentityRoleRepository : MongoDbRepository<IAbpIdentityMongoDb
.As<IMongoQueryable<IdentityRole>>()
.LongCountAsync(GetCancellationToken(cancellationToken));
}
protected virtual async Task<List<IdentityRole>> GetListInternalAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string filter = null,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.WhereIf(!filter.IsNullOrWhiteSpace(),
x => x.Name.Contains(filter) ||
x.NormalizedName.Contains(filter))
.OrderBy(sorting.IsNullOrWhiteSpace() ? nameof(IdentityRole.Name) : sorting)
.As<IMongoQueryable<IdentityRole>>()
.PageBy<IdentityRole, IMongoQueryable<IdentityRole>>(skipCount, maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken));
}
}

@ -268,26 +268,7 @@ public class MongoIdentityUserRepository : MongoDbRepository<IAbpIdentityMongoDb
.WhereIf<IdentityUser, IMongoQueryable<IdentityUser>>(minModifitionTime != null, p => p.LastModificationTime >= minModifitionTime)
.LongCountAsync(GetCancellationToken(cancellationToken));
}
public async Task<List<RoleWithUserCount>> GetCountAsync(Guid[] roleIds, CancellationToken cancellationToken = default)
{
var users = await (await GetMongoQueryableAsync(cancellationToken))
.Where(user => user.Roles.Any(role => roleIds.Contains(role.RoleId)))
.ToListAsync(GetCancellationToken(cancellationToken));
var result = new List<RoleWithUserCount>();
foreach (var roleId in roleIds)
{
result.Add(new RoleWithUserCount
{
RoleId = roleId,
UserCount = users.Count(t => t.Roles.Any(role => role.RoleId == roleId))
});
}
return result;
}
public virtual async Task<List<IdentityUser>> GetUsersInOrganizationUnitAsync(
Guid organizationUnitId,
CancellationToken cancellationToken = default)
@ -318,7 +299,7 @@ public class MongoIdentityUserRepository : MongoDbRepository<IAbpIdentityMongoDb
.Where(ou => ou.Code.StartsWith(code))
.Select(ou => ou.Id)
.ToListAsync(cancellationToken);
return await (await GetMongoQueryableAsync(cancellationToken))
.Where(u => u.OrganizationUnits.Any(uou => organizationUnitIds.Contains(uou.OrganizationUnitId)))
.ToListAsync(cancellationToken);

@ -66,4 +66,16 @@ public abstract class IdentityRoleRepository_Tests<TStartupModule> : AbpIdentity
role.Claims.ShouldNotBeNull();
role.Claims.Any().ShouldBeTrue();
}
[Fact]
public async Task GetListWithUserCountAsync()
{
var roles = await RoleRepository.GetListWithUserCountAsync();
roles.Count.ShouldBe(4);
roles.ShouldContain(r => r.Role.Name == "admin" && r.UserCount == 2);
roles.ShouldContain(r => r.Role.Name == "moderator" && r.UserCount == 1);
roles.ShouldContain(r => r.Role.Name == "supporter" && r.UserCount == 2);
roles.ShouldContain(r => r.Role.Name == "manager" && r.UserCount == 1);
}
}

@ -135,16 +135,6 @@ public abstract class IdentityUserRepository_Tests<TStartupModule> : AbpIdentity
(await UserRepository.GetCountAsync("n")).ShouldBeGreaterThan(1);
(await UserRepository.GetCountAsync("undefined-username")).ShouldBe(0);
}
[Fact]
public async Task GetCountAsync_With_RoleIds()
{
var roleWithUserCounts = await UserRepository.GetCountAsync(roleIds: new []{ TestData.RoleModeratorId, TestData.RoleSupporterId });
roleWithUserCounts.Count.ShouldBe(2);
roleWithUserCounts.ShouldContain(e => e.RoleId == TestData.RoleModeratorId && e.UserCount == 1);
roleWithUserCounts.ShouldContain(e => e.RoleId == TestData.RoleSupporterId && e.UserCount == 2);
}
[Fact]
public async Task GetUsersInOrganizationUnitAsync()

Loading…
Cancel
Save