1 Services.Customers.CustomerServiceDefaults
/// <summary>
/// 【1个指定用户所对应的所有角色缓存键】
/// <remarks>
/// 摘要:
/// 设定一个缓存键实例,用于拼接1个指定的缓存键字符串,该缓存键字符与角色实体所有实例两者构建了缓存映射关系。
/// {0} :1个指定用户所对应的整型编号值。
/// {1} : 布尔值字符串,为缓存键字符串的拼接提供数据支撑,如果该布尔值字符串为:“True”,则缓存键字符所对应缓存项中存储着角色实体的所有实例;
/// 如果该布尔值字符串为:“False”,则缓存键字符所对应缓存项中存储着处于激活状态的角色实体的所有实例。
/// </remarks>
/// </summary>
public static CacheKey RolesCacheKey => new("customer.role.{0}-{1}", RolesByCustomerPrefix, CustomerRolesPrefix);
/// <summary>
/// 【1个指定用户所对应的所有角色前缀】
/// <remarks>
/// 摘要:
/// 设定一个缓存键实例,用于拼接1个指定的缓存键字符串,该缓存键字符与角色实体所有实例两者构建了缓存映射关系。
/// </remarks>
/// </summary>
public static string CustomerRolesPrefix => "customer.role.";
/// <summary>
/// 【1个指定用户所对应的所有角色前缀】
/// <remarks>
/// 摘要:
/// 设定一个缓存键实例,用于拼接1个指定的缓存键字符串,该缓存键字符与角色实体所有实例两者构建了缓存映射关系。
/// {0} :1个指定用户所对应的整型编号值。
/// </remarks>
/// </summary>
public static string RolesByCustomerPrefix => "customer.role.{0}";
2 重构Services.Customers.Caching.CustomerCacheEventConsumer
using Core.Domain.Customers;
using Services.Caching;
namespace Services.Customers.Caching
{
/// <summary>
/// 摘要:
/// 通过该类中的方法成员,在用户实体的1个实例执行插入、更新或持久化/逻辑删除操作后,为该实体所有相关实例的分布式缓存的强制移除操作提供数据支撑,同时避免用户实体的列表渲染显示出现的异常。
/// </summary>
public class CustomerCacheEventConsumer : CacheEventConsumer<Customer>
{
/// <param name="entity">用户实体的1个指定实例。</param>
/// <summary>
/// 【异步清理缓存】
/// <remarks>
/// 摘要:
/// 执行插入、更新或删除操作时,从分布式数据库中强制移除该方法中所有指定的所有缓存项(键/(“JSON”编码格式的)值对)或字典实例中强制移除该方法中所有指定的所有键/值对。
/// </remarks>
/// </summary>
protected override async Task ClearCacheAsync(Customer entity)
{
await RemoveByPrefixAsync(CustomerServicesDefaults.RolesByCustomerPrefix, entity);
}
}
}
3 重构Services.Customers.Caching.RoleCacheEventConsumer
using Core.Domain.Customers;
using Services.Caching;
namespace Services.Customers.Caching
{
/// <summary>
/// 摘要:
/// 通过该类中的方法成员,在角色实体的1个实例执行插入、更新或持久化/逻辑删除操作后,为该实体所有相关实例的分布式缓存的强制移除操作提供数据支撑,同时避免角色实体的列表渲染显示出现的异常。
/// </summary>
public class RoleCacheEventConsumer : CacheEventConsumer<Role>
{
/// <param name="entity">角色实体的1个指定实例。</param>
/// <summary>
/// 【异步清理缓存】
/// <remarks>
/// 摘要:
/// 执行插入、更新或删除操作时,从分布式数据库中强制移除该方法中所有指定的所有缓存项(键/(“JSON”编码格式的)值对)或字典实例中强制移除该方法中所有指定的所有键/值对。
/// </remarks>
/// </summary>
protected override async Task ClearCacheAsync(Role entity)
{
await RemoveByPrefixAsync(CustomerServicesDefaults.CustomerRolesPrefix);
}
}
}
4 Services.Customers.Caching.CustomerRoleCacheEventConsumer
using Core.Domain.Customers;
using Services.Caching;
namespace Services.Customers.Caching
{
/// <summary>
/// 摘要:
/// 通过该类中的方法成员,在用户角色映射实体的1个实例执行插入、更新或持久化/逻辑删除操作后,为该实体所有相关实例的分布式缓存的强制移除操作提供数据支撑,同时避免用户角色映射实体的列表渲染显示出现的异常。
/// </summary>
public partial class CustomerRoleCacheEventConsumer : CacheEventConsumer<CustomerRole>
{
/// <param name="entity">用户角色映射实体的1个指定实例。</param>
/// <summary>
/// 【异步清理缓存】
/// <remarks>
/// 摘要:
/// 执行插入、更新或删除操作时,从分布式数据库中强制移除该方法中所有指定的所有缓存项(键/(“JSON”编码格式的)值对)或字典实例中强制移除该方法中所有指定的所有键/值对。
/// </remarks>
/// </summary>
protected override async Task ClearCacheAsync(CustomerRole entity)
{
await RemoveByPrefixAsync(CustomerServicesDefaults.CustomerRolesPrefix);
}
}
}
5 Services.Customers.CustomerService.GetRolesAsync
/// <param name="customer">用户实体的1个指定实例。</param>
/// <param name="showHidden">指示是否获取角色实体的所有实例,默认值:false,即只获取处于激活状态的角色实体的所有实例。</param>
/// <summary>
/// 【异步获取1个指定用户的所有角色】
/// <remarks>
/// 摘要:
/// 直接从角色表中1个指定用户的所有角色实例;或从分布式缓存数据库获取1个指定用户的所有角色实例。
/// </remarks>
/// <returns>
/// 列表实例,该实例存储着1个指定用户的所有角色实例。
/// </returns>
/// </summary>
public virtual async Task<IList<Role>> GetRolesAsync(Customer customer, bool showHidden = false)
{
if (customer == null)
throw new ArgumentNullException(nameof(customer));
return await _roleRepository.GetAllAsync(query =>
{
return from role in query
join customerRole in _customerRoleRepository.Table on role.Id equals customerRole.RoleId
where customerRole.CustomerId == customer.Id &&
(showHidden || role.Active)
select role;
}, cache => cache.PrepareKeyForShortTermCache(CustomerServicesDefaults.RolesCacheKey, customer, showHidden));
}
6 重构Web.Areas.Admin.Factories.CustomerModelFactory.PrepareCustomerListModelAsync
public virtual async Task<CustomerListModel> PrepareCustomerListModelAsync(CustomerSearchModel searchModel)
{
var createdTo = !searchModel.CreatedDateTo.HasValue ? null
: searchModel.CreatedDateTo?.AddDays(1);
//根据前端传递的用户过滤筛选模型纪录的1个指定实例,从用户表中获取(1逻辑页中的)相应行数的数据,并把这些数据存储到列表实例中。
var customers = await _customerService.GetAllCustomersAsync(
deleted: searchModel.Deleted,
email: searchModel.Email,
username: searchModel.Username,
phone: searchModel.Phone,
createdDateFrom: searchModel.CreatedDateFrom,
createdDateTo: createdTo,
orderByFiled: searchModel.OrderBy,
orderByType: searchModel.OrderDir.ToString(),
pageIndex: searchModel.Page - 1,
pageSize: searchModel.PageSize);
//实例化当前用户分页列表模型纪录(“物理页”),为Jquery DataTable插件当前页渲染显示提供基本且必须的数据支撑。
var model = await new CustomerListModel().PrepareToGridAsync(searchModel, customers, () =>
{
return customers.SelectAwait(async customer =>
{
var customerModel = customer.ToModel<CustomerModel>();
customerModel.Avatar = GetAbsoluteAvatarUrl(customerModel.Avatar);
customerModel.RoleNames = string.Join(", ",(await _customerService.GetRolesAsync(customer)).Select(role => role.Name));
return customerModel;
});
});
return model;
}
7 重构Web\Areas\Admin\Views\Customer\Index.cshtml
{ data: "phone", title: "手机", width: "100px", orderable: false },
{
data: "roleNames",
title: "角色",
width: "100px",
orderable: false,
//禁止当前列渲染显示排序按钮。
render: function (data, type, row, full, meta) {
var roleArray = data.split(",");
var roleHtml = "";
$.each(roleArray, function () {
roleHtml += "<span class='badge bg-info'>" + this + "</span><br/>"
});
return roleHtml;
},
},
对以上功能更为具体实现和注释见230602_021ShopRazor(JQuery DataTables对角色的渲染显示)。