1 为什么逻辑分页不使用分布式缓存进行存储?
1、首先必须明白逻辑分页不使用分布式缓存进行存储不是技术层面的因素,在技术层面完全可以把逻辑分页数据通过分布式缓存数据库进行存储和管理。
2、由于逻辑分页操作需要频繁的把数据库指定表中的持久化数据加载到内存中,以便程序使用,如果再把这些数据通过分布式缓存数据库进行存储和管理,不但不能达能增加程序响应速度的目的,反而有极大概率上会增加内存消耗拖慢程序的响应速度的反效果。
3、如果把逻辑分页操作所产生的数据通过分布式缓存数据库进行存储和管理,由于短时间内不会对内存中的数据进行销毁,导致持续不断的增加内存资源的消耗,会由于内存资源的耗尽,从而会造成内存的溢出,最终操作系统的崩溃,这种现象在基于网络实现的程序上会以惊人的速度呈现出来。这是逻辑分页不使用分布式缓存进行存储的物理因素。
4、使用分布式缓存数据库进行存储和管理的持久化数据的基本指导性原则有:在短时间内持久化数据不会发生改变,且不能频繁的加载到内存;例如:登录操作执行后的用户信息数据、角色实体的实例、产品类型实体的实例等;与之相对的则是:用户所有实例的分页操作、产品所有实例的分页操作等。
5、其实在Vue中的全局存储(store/index.js)也是一种特殊的用分布式缓存数据库进行存储和管理的技术实现,因为它也是通过键/值所构建的缓存项把登录操作执行后的用户信息数据、角色实体的实例、产品类型实体的实例等数据在一段时间内存储在内存中并进行相应的管理工作。二者只有应用场景的区别而无技术实质的区别:一个用于后端程序数据的存储和管理;另有用于前端程序数据的存储和管理。
2 Services.Customers.CustomerService.GetAllCustomersAsync
/// <param name="email">1个指定的电字邮箱字符串,默认值:null,即该参数实例不参与筛选操作。</param>
/// <param name="name">1个指定的用户名/昵称,默认值:null,即该参数实例不参与筛选操作。</param>
/// <param name="phone">个指定的手机号,默认值:null,即该参数实例不参与筛选操作。</param>
/// <param name="isSystemAccount">指示是否只获取是系统帐户的所有实例,默认值:null,即该参数实例不参与筛选操作。</param>
/// <param name="isActive">指示是否只获取已经处于激活状态的所有实例,默认值:null,即该参数实例不参与筛选操作。</param>
/// <param name="isDeleted">指示是否只获取已经处于逻辑删除状态的所有实例,默认值:null,即该参数实例不参与筛选操作。</param>
/// <param name="orderByFiled">1个指定的用于排序操作的排序字段字符串,默认值:null,即按照创建时间以倒序方式进行排序操作。</param>
/// <param name="orderByType">1个指定的用于排序操作的排序排序方式,默认值:null,即按照创建时间以倒序方式进行排序操作。</param>
/// <param name="pageIndex">当前页的页数值(与“pageSize”结合,设定需要跳过指定实体实例的个数值),默认值:0,即不需要执行跳过操作。</param>
/// <param name="pageSize">分页操作中每页最多显示实例的项(行)数值(与“pageIndex”结合,设定需要跳过指定实体实例的个数值),默认值:int.MaxValue=2147483647。</param>
/// <summary>
/// 【异步获取所有用户】
/// <remarks>
/// 摘要:
/// 根据前端分页组件传递的参数实例,获取符合条件的用户表1指定页面内的持久化数据加载到1指定内存逻辑页面内。
/// 说明:
/// 该方法没有定义缓存操作,更没有定义缓存的移除操作。
/// </remarks>
/// <returns>
/// 返回:
/// 1指定内存逻辑页面内的用户实体的所有实例。
/// </returns>
/// </summary>
public virtual async Task<IPagedList<Customer>> GetAllCustomersAsync(string email = null, string name = null,
string phone = null, bool? isSystemAccount = null, bool? isActive = null, bool? isDeleted = null,
string orderByFiled = null, string orderByType = null, long pageIndex = 0, int pageSize = int.MaxValue)
{
return await _customerRepository.GetAllPagedAsync(query =>
{
//根据参数实例,执行筛选操作。
if (!string.IsNullOrWhiteSpace(email))
query = query.Where(customer => customer.Email.Contains(email));
if (!string.IsNullOrWhiteSpace(name))
query = query.Where(customer => customer.Name.Contains(name));
if (!string.IsNullOrWhiteSpace(phone))
query = query.Where(customer => customer.Phone.Contains(phone));
if (isSystemAccount.HasValue)
query = query.Where(customer => customer.IsSystemAccount == isSystemAccount);
if (isActive.HasValue)
query = query.Where(customer => customer.IsActive == isActive);
if (isDeleted.HasValue)
query = query.Where(customer => customer.Deleted == isDeleted);
//根据参数实例,执行排序操作。
if (string.IsNullOrWhiteSpace(orderByFiled) && string.IsNullOrWhiteSpace(orderByType))
{
query = query.OrderByDescending(customer => customer.CreatedDateTime);
}
else if (!string.IsNullOrWhiteSpace(orderByFiled))
{
if (orderByType.Equals("ascending", StringComparison.InvariantCultureIgnoreCase))
{
query.OrderBy(orderByFiled);
}
else if (orderByType.Equals("descending", StringComparison.InvariantCultureIgnoreCase))
{
query.OrderByDescending(orderByFiled);
}
}
return query;
}, pageIndex, pageSize);
}
3 WebApi.Models.Customer.CustomerSearchModel
namespace WebApi.Models.Customer
{
/// <summary>
/// 【用户过滤筛选模型--纪录】
/// <remarks>
/// 摘要:
/// 通过该纪录中的属性成员实例为指定数据库中的用户表的过滤筛选操作提供数据支撑。
/// </remarks>
/// </summary>
public record CustomerSearchModel
{
/// <summary>
/// 【用户名】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定的用户名(账户、昵称)。
/// 说明:
/// 为使该属性的实例有可能不参与排序操作,该属性的默认实例被设定为:null。
/// </remarks>
/// </summary>
public string Name { get; set; } = null;
/// <summary>
/// 【电子邮箱】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定用户所对应的电子邮箱。
/// 说明:
/// 为使该属性的实例有可能不参与排序操作,该属性的默认实例被设定为:null。
/// </remarks>
/// </summary>
public string Email { get; set; } = null;
/// <summary>
/// 【手机号】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定用户所对应的手机号。
/// 说明:
/// 为使该属性的实例有可能不参与排序操作,该属性的默认实例被设定为:null。
/// </remarks>
/// </summary>
public string Phone { get; set; } = null;
/// <summary>
/// 【系统帐户?】
/// <remarks>
/// 摘要:
/// 获取/设置1个值false(默认值:不是)/true(是),该值指示用户实体的1个指定实例是否是系统帐户。
/// 说明:
/// 1、为使该属性的实例有可能不参与过滤筛选操作,该属性被定义为了可空类型且默认实例被设定为:null。
/// 2、如果是系统帐户,则该用户将不能被物理/逻辑删除,即在删除操作中会通过该属性实例过滤掉系统帐户的所有用户。
/// </remarks>
/// </summary>
public bool? IsSystemAccount { get; set; }= null;
/// <summary>
/// 【启用?】
/// <remarks>
/// 摘要:
/// 获取/设置1个值false(禁用)/true(默认值:启用),该值指示用户实体的1个指定实例是否处于启用状态。
/// 说明:
/// 1、为使该属性的实例有可能不参与过滤筛选操作,该属性被定义为了可空类型且默认实例被设定为:null。
/// </remarks>
/// </summary>
public bool? IsActive { get; set; } = null;
/// <summary>
/// 【(逻辑)删除?】
/// <remarks>
/// 摘要:
/// 获取/设置1个值false(未(逻辑)删除)/true(已经(逻辑)删除),该值指示用户实体的1个指定实例是否已经处于(逻辑)删除状态。
/// 说明:
/// 1、为使该属性的实例有可能不参与过滤筛选操作,该属性被定义为了可空类型且默认实例被设定为:null。
/// </remarks>
/// </summary>
public bool? IsDeleted { get; set; } = null;
}
}
4 WebApi.Models.OrderByModel
namespace WebApi.Models
{
/// <summary>
/// 【排序模型--纪录】
/// <remarks>
/// 摘要:
/// 通过该纪录中的属性成员实例为指定数据库中的指定表的排序操作提供数据支撑。
/// </remarks>
/// </summary>
public record OrderByModel
{
/// <summary>
/// 【排序字段】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定的用于排序操作的字段。
/// 说明:
/// 为使该属性的实例有可能不参与排序操作,该属性的默认实例被设定为:null。
/// </remarks>
/// </summary>
public string OrderByFiled { get; set; } = null;
/// <summary>
/// <summary>
/// 【排序方式】
/// <remarks>
/// 摘要:
/// 获取/设置1个指定的用于操作操作的排序方式:正序/倒序。
/// 说明:
/// 为使该属性的实例有可能不参与排序操作,该属性的默认实例被设定为:null。
/// </remarks>
/// </summary>
public string OrderByType { get; set; } = null;
}
}
5 WebApi.Controllers.CustomerController.Index
/// <param name="pagination">分页模型纪录的1个指定实例。</param>
/// <summary>
/// 【用户表单单击提交分页--需权限】
/// </summary>
/// <remarks>
/// 摘要:
/// 通过分页控件所传递的参数实例,获取符合条件的1指定页面内的所有数据,为指定页面的渲染显示提供数据支撑。
/// 注意:
/// 表单提交分页必须使用“[HttpPost]”进行标记。
/// </remarks>
/// <returns>
/// 返回:
/// 消息模型纪录的1个指定实例,该实例存储当前“Api”方法的执行操作结果,为客户端页面的渲染提供数据支撑。
/// </returns>
//[Authorize(Policy = "OnlyInAdministrator")]
//[Authorize(PermissionsPolicy.Name)]
[HttpPost]
public async Task<MessageModel<PageModel<Customer>>> Index([FromBody] PaginationModel pagination)
{
CustomerSearchModel _customerSearchModel = new CustomerSearchModel();
if (!string.IsNullOrEmpty(pagination.QueryCondition))
_customerSearchModel = JsonConvert.DeserializeAnonymousType(pagination.QueryCondition, _customerSearchModel);
OrderByModel _orderByModel = new OrderByModel();
if (!string.IsNullOrEmpty(pagination.OrderByModel))
_orderByModel = JsonConvert.DeserializeAnonymousType(pagination.OrderByModel, _orderByModel);
//根据前端分页组件传递的参数实例,从角色表中获取(1逻辑页中的)相应行数的数据,并把这些数据存储到列表实例中。
IPagedList<Customer> _customerPageList = await _customerService.GetAllCustomersAsync(_customerSearchModel.Email,
_customerSearchModel.Name,
_customerSearchModel.Phone,
_customerSearchModel.IsSystemAccount,
_customerSearchModel.IsActive,
_customerSearchModel.IsDeleted,
_orderByModel.OrderByFiled,
_orderByModel.OrderByType,
(pagination.PageIndex - 1),
pagination.PageSize);
//实例化当前模型页(“物理页”),为当前页面的渲染显示提供数据支撑。
PageModel<Customer> _customerPageModel = new PageModel<Customer>()
{
PageIndex = pagination.PageIndex,
PageSize = pagination.PageSize,
TotalCount = _customerPageList.TotalCount,
Data = _customerPageList,
};
//实例化消息模型录,对当前“Api”控制器行方法的执行操作结果进行存储,为客户端页面的渲染提供数据支撑。
return MessageModel<PageModel<Customer>>.GetSuccess($"成功获取第{pagination.PageIndex}页内的所有用户!", _customerPageModel);
}
6 分页测试组合
{
"pageIndex": 1,
"pageSize": 10,
"orderByModel": "",
"queryCondition": ""
}
{
"pageIndex": 1,
"pageSize": 10,
"orderByModel": "",
"queryCondition": "{\"Name\":\"张\"}"
}
{
"pageIndex": 1,
"pageSize": 10,
"orderByModel": "{\"OrderByFiled\":\"id\",\"OrderByType\":\"ascending\"}",
"queryCondition": "{\"Name\":\"张\",\"IsSystemAccount\":true}"
}
{
"pageIndex": 1,
"pageSize": 10,
"orderByModel": "{\"OrderByFiled\":\"id\",\"OrderByType\":\"ascending\"}",
"queryCondition": "{\"Name\":\"张\",\"IsSystemAccount\":true,\"IsActive\":true}"
}
{
"pageIndex": 1,
"pageSize": 10,
"orderByModel": "{\"OrderByFiled\":\"id\",\"OrderByType\":\"ascending\"}",
"queryCondition": "{\"Name\":\"张\",\"IsSystemAccount\":true,\"IsActive\":true,\"IsDeleted\":false}"
}
对以上功能更为具体实现和注释见:230223_041shopDemo(所有用户实例的分页实现)。