• 利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理


    在Asp.net Web API中,对业务数据的分页查询处理是一个非常常见的接口,我们需要在查询条件对象中,定义好相应业务的查询参数,排序信息,请求记录数和每页大小信息等内容,根据这些查询信息,我们在后端的Asp.net Web API中实现对这些数据的按需获取,并排序返回给客户端使用。本篇随笔介绍利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理。

    1、Web API控制器基类关系

    为了更好的进行相关方法的封装处理,我们把一些常规的接口处理放在BaseApiController里面,而把基于业务表的操作接口放在BusinessController里面定义,如下所示。

    在BaseApiController里面,我们使用了结果封装和异常处理的过滤器统一处理,以便简化代码,如下控制器类定义。

        /// <summary>
        /// 所有接口基类
        /// </summary>
        [ExceptionHandling]
        [WrapResult]
        public class BaseApiController : ApiController

    其中ExceptionHandling 和WrapResult的过滤器处理,可以参考我的随笔《利用过滤器Filter和特性Attribute实现对Web API返回结果的封装和统一异常处理》进行详细了解。

    而业务类的接口通用封装,则放在了BusinessController控制器里面,其中使用了泛型定义,包括实体类,业务操作类,分页条件类等内容作为约束参数,如下所示。

        /// <summary>
        /// 本控制器基类专门为访问数据业务对象而设的基类
        /// </summary>
        /// <typeparam name="B">业务对象类型</typeparam>
        /// <typeparam name="T">实体类类型</typeparam>
        [ApiAuthorize]
        public class BusinessController<B, T, TGetAllInput> : BaseApiController
            where B : class
            where TGetAllInput : IPagedAndSortedResultRequest
            where T : BaseEntity, new()

    2、分页处理接口

    其中IPagedAndSortedResultRequest接口,是借鉴ABP框架中对于分页部分的处理,因此分页函数需要实现这个接口,这个接口包含了请求的数量,偏移量, 以及排序等属性定义的。

    而BusinessController的分页查询处理函数GetAll定义如下所示。

            /// <summary>
            /// 分页获取记录
            /// </summary>
            /// <param name="input"></param>
            /// <returns></returns>
            [HttpGet]
            public virtual PagedResultDto<T> GetAll([FromUri] TGetAllInput input)
            {
                var condition = GetCondition(input);
                var list = GetPagedData(condition, input);
                return list;
            }

    其中 GetCondition 函数是给子类进行重写,以便处理不同的条件查询的。我们以UserController控制器为例进行说明。

        /// <summary>
        /// 用户信息的业务控制器
        /// </summary>
        public class UserController : BusinessController<User, UserInfo, UserPagedDto>

    其中传入的User是BLL业务层类,用来操作数据库;UserInfo是实体类,用来传递记录信息;UserPagedDto 则是分页查询条件类。

        /// <summary>
        /// 用户信息的业务查询类
        /// </summary>
        public class UserPagedDto : PagedAndSortedInputDto, IPagedAndSortedResultRequest
        {
            /// <summary>
            /// 默认构造函数
            /// </summary>
            public UserPagedDto() : base() { }
    
            /// <summary>
            /// 参数化构造函数
            /// </summary>
            /// <param name="skipCount">跳过的数量</param>
            /// <param name="resultCount">最大结果集数量</param>
            public UserPagedDto(int skipCount, int resultCount) : base(skipCount, resultCount)
            {
            }
    
            /// <summary>
            /// 使用分页信息进行初始化SkipCount 和 MaxResultCount
            /// </summary>
            /// <param name="pagerInfo">分页信息</param>
            public UserPagedDto(PagerInfo pagerInfo) : base(pagerInfo)
            {
            }
    
            #region Property Members
            /// <summary>
            /// 所属角色ID
            /// </summary>
            public virtual int? Role_ID { get; set; }
    
            public virtual int? ID { get; set; }
    
            /// <summary>
            /// 用户编码
            /// </summary>
            public virtual string HandNo { get; set; }
    
            /// <summary>
            /// 用户名/登录名
            /// </summary>
            public virtual string Name { get; set; }
    
            /// <summary>
            /// 用户密码
            /// </summary>
            public virtual string Password { get; set; }
    
            /// <summary>
            /// 用户全名
            /// </summary>
            public virtual string FullName { get; set; }
    
            /// <summary>
            /// 移动电话
            /// </summary>
            public virtual string MobilePhone { get; set; }
    
            /// <summary>
            /// 邮件地址
            /// </summary>
            public virtual string Email { get; set; }
    
            /// <summary>
            /// 默认部门ID
            /// </summary>
            public virtual string Dept_ID { get; set; }
    
            /// <summary>
            /// 所属机构ID
            /// </summary>
            public virtual string Company_ID { get; set; }
    
            /// <summary>
            /// 父ID
            /// </summary>
            public virtual int? PID { get; set; }
    
            /// <summary>
            /// 用户呢称
            /// </summary>
            public virtual string Nickname { get; set; }
    
            /// <summary>
            /// 是否过期
            /// </summary>
            public virtual bool? IsExpire { get; set; }
    
            /// <summary>
            /// 过期日期
            /// </summary>
            public virtual DateTime? ExpireDateStart { get; set; }
            public virtual DateTime? ExpireDateEnd { get; set; }
    
            /// <summary>
            /// 职务头衔
            /// </summary>
            public virtual string Title { get; set; }
    
            /// <summary>
            /// 身份证号码
            /// </summary>
            public virtual string IdentityCard { get; set; }
    
            /// <summary>
            /// 办公电话
            /// </summary>
            public virtual string OfficePhone { get; set; }
    
            /// <summary>
            /// 家庭电话
            /// </summary>
            public virtual string HomePhone { get; set; }
    
            /// <summary>
            /// 住址
            /// </summary>
            public virtual string Address { get; set; }
    
            /// <summary>
            /// 办公地址
            /// </summary>
            public virtual string WorkAddr { get; set; }
    
            /// <summary>
            /// 性别
            /// </summary>
            public virtual string Gender { get; set; }
    
            /// <summary>
            /// 出生日期
            /// </summary>
            public virtual DateTime? BirthdayStart { get; set; }
            public virtual DateTime? BirthdayEnd { get; set; }
    
            /// <summary>
            /// QQ号码
            /// </summary>
            public virtual string QQ { get; set; }
    
            /// <summary>
            /// 个性签名
            /// </summary>
            public virtual string Signature { get; set; }
    
            /// <summary>
            /// 审核状态
            /// </summary>
            public virtual string AuditStatus { get; set; }
    
            /// <summary>
            /// 备注
            /// </summary>
            public virtual string Note { get; set; }
    
            /// <summary>
            /// 自定义字段
            /// </summary>
            public virtual string CustomField { get; set; }
    
            /// <summary>
            /// 默认部门名称
            /// </summary>
            public virtual string DeptName { get; set; }
    
            /// <summary>
            /// 所属机构名称
            /// </summary>
            public virtual string CompanyName { get; set; }
    
            /// <summary>
            /// 排序码
            /// </summary>
            public virtual string SortCode { get; set; }
    
            /// <summary>
            /// 创建人
            /// </summary>
            public virtual string Creator { get; set; }
    
            /// <summary>
            /// 创建人ID
            /// </summary>
            public virtual string Creator_ID { get; set; }
    
            /// <summary>
            /// 创建时间
            /// </summary>
            public virtual DateTime? CreateTimeStart { get; set; }
            public virtual DateTime? CreateTimeEnd { get; set; }
    
            /// <summary>
            /// 编辑人
            /// </summary>
            public virtual string Editor { get; set; }
    
            /// <summary>
            /// 编辑人ID
            /// </summary>
            public virtual string Editor_ID { get; set; }
    
            /// <summary>
            /// 编辑时间
            /// </summary>
            public virtual DateTime? EditTimeStart { get; set; }
            public virtual DateTime? EditTimeEnd { get; set; }
    
            /// <summary>
            /// 是否已删除
            /// </summary>
            public virtual bool? Deleted { get; set; }
    
            /// <summary>
            /// 当前登录IP
            /// </summary>
            public virtual string CurrentLoginIP { get; set; }
    
            /// <summary>
            /// 当前登录时间
            /// </summary>
            public virtual DateTime CurrentLoginTime { get; set; }
    
            /// <summary>
            /// 当前Mac地址
            /// </summary>
            public virtual string CurrentMacAddress { get; set; }
    
            /// <summary>
            /// 微信绑定的OpenId
            /// </summary>
            public virtual string OpenId { get; set; }
    
            /// <summary>
            /// 微信多平台应用下的统一ID
            /// </summary>
            public virtual string UnionId { get; set; }
    
            /// <summary>
            /// 公众号状态
            /// </summary>
            public virtual string Status { get; set; }
    
            /// <summary>
            /// 公众号
            /// </summary>
            public virtual string SubscribeWechat { get; set; }
    
            /// <summary>
            /// 科室权限
            /// </summary>
            public virtual string DeptPermission { get; set; }
    
            /// <summary>
            /// 企业微信UserID
            /// </summary>
            public virtual string CorpUserId { get; set; }
    
            /// <summary>
            /// 企业微信状态
            /// </summary>
            public virtual string CorpStatus { get; set; }
    
            #endregion
        }

    它的基类属性包括了MaxResultCount,SkipCount,Sorting等分页排序所需的信息。

    另外还包含了对条件查询的属性信息,如果是数值的,布尔类型的,则是可空类型,日期则有起始条件的范围属性等等,也可以根据自己需要定义更多属性用户过滤条件。

    如对于出生日期,我们定义一个区间范围来进行查询。

            /// <summary>
            /// 出生日期
            /// </summary>
            public virtual DateTime? BirthdayStart { get; set; }
            public virtual DateTime? BirthdayEnd { get; set; }

    最后,我们根据需要进行判断,获得查询条件即可。

            /// <summary>
            /// 获取查询条件并转换为SQL
            /// </summary>
            /// <param name="input">查询条件</param>
            protected override string GetCondition(UserPagedDto input)
            {
                //根据条件,构建SQL条件语句
                SearchCondition condition = new SearchCondition();
                if (!input.Role_ID.HasValue)
                {
                    condition.AddCondition("ID", input.ID, SqlOperator.Equal)
                        .AddCondition("IdentityCard", input.IdentityCard, SqlOperator.Equal)
                        .AddCondition("Name", input.Name, SqlOperator.Like)
                        .AddCondition("Note", input.Note, SqlOperator.Like)
                        .AddCondition("Email", input.Email, SqlOperator.Like)
                        .AddCondition("MobilePhone", input.MobilePhone, SqlOperator.Like)
                        .AddCondition("Address", input.Address, SqlOperator.Like)
                        .AddCondition("HandNo", input.HandNo, SqlOperator.Like)
                        .AddCondition("HomePhone", input.HomePhone, SqlOperator.Like)
                        .AddCondition("Nickname", input.Nickname, SqlOperator.Like)
                        .AddCondition("OfficePhone", input.OfficePhone, SqlOperator.Like)
                        .AddCondition("OpenId", input.OpenId, SqlOperator.Like)
                        .AddCondition("Password", input.Password, SqlOperator.Like)
                        .AddCondition("PID", input.PID, SqlOperator.Like)
                        .AddCondition("QQ", input.QQ, SqlOperator.Equal)
                        .AddCondition("DeptPermission", input.DeptPermission, SqlOperator.Like)
                        .AddCondition("AuditStatus", input.AuditStatus, SqlOperator.Equal)
                        .AddCondition("FullName", input.FullName, SqlOperator.Like)
                        .AddCondition("Gender", input.Gender, SqlOperator.Equal)
                        .AddCondition("CustomField", input.CustomField, SqlOperator.Like)
                        .AddCondition("IsExpire", input.IsExpire, SqlOperator.Equal)
                        .AddCondition("Signature", input.Signature, SqlOperator.Like)
                        .AddCondition("SortCode", input.SortCode, SqlOperator.Like)
                        .AddCondition("Status", input.Status, SqlOperator.Equal)
                        .AddCondition("CorpStatus", input.CorpStatus, SqlOperator.Equal)
                        .AddCondition("CorpUserId", input.CorpUserId, SqlOperator.Equal)
                        .AddCondition("UnionId", input.UnionId, SqlOperator.Equal)
                        .AddCondition("WorkAddr", input.WorkAddr, SqlOperator.Equal)
                        .AddCondition("SubscribeWechat", input.SubscribeWechat, SqlOperator.Equal)
                        .AddCondition("Title", input.Title, SqlOperator.Like)
                        .AddCondition("CurrentLoginIP", input.CurrentLoginIP, SqlOperator.Like)
                        .AddCondition("CurrentMacAddress", input.CurrentMacAddress, SqlOperator.Like)
    
                        .AddCondition("Dept_ID", input.Dept_ID, SqlOperator.Equal)
                        .AddCondition("DeptName", input.DeptName, SqlOperator.Like)
                        .AddCondition("CompanyName", input.CompanyName, SqlOperator.Like)
                        .AddCondition("Company_ID", input.Company_ID, SqlOperator.Equal)
                        .AddCondition("Editor_ID", input.Editor_ID, SqlOperator.Equal)
                        .AddCondition("Editor", input.Editor, SqlOperator.Equal)
                        .AddCondition("Creator_ID", input.Creator_ID, SqlOperator.Equal)
                        .AddCondition("Creator", input.Creator, SqlOperator.Equal)
    
                        .AddDateCondition("CreateTime", input.CreateTimeStart, input.CreateTimeEnd)
                        .AddDateCondition("EditTime", input.EditTimeStart, input.EditTimeEnd)
                        .AddDateCondition("ExpireDate", input.ExpireDateStart, input.ExpireDateEnd)
                        .AddDateCondition("Birthday", input.BirthdayStart, input.BirthdayEnd);
                }
    
                return condition.BuildConditionSql().Replace("Where", "");
            }

    前面介绍到,我们BusinessController基类定义了常规的分页查询GetAll函数,如下所示。

            /// <summary>
            /// 分页获取记录
            /// </summary>
            /// <param name="input"></param>
            /// <returns></returns>
            [HttpGet]
            public virtual PagedResultDto<T> GetAll([FromUri] TGetAllInput input)
            {
                var condition = GetCondition(input);
                var list = GetPagedData(condition, input);
                return list;
            }

    其中 GetCondition 是由子类进行重写处理,生成具体的查询条件的。

    由于这里的Sorting信息是一个字符串的排序信息,如 Name DESC或者Name ASC类似的信息,前者是字段名,后者是排序降序还是升序的标识,我们在业务里面,需要拆分一下进行组合条件,如下拆分。

                //分页查询条件
                string sortName = null; //排序字段
                bool isDesc = true;
                if (!string.IsNullOrEmpty(input.Sorting))
                {
                    var sortInput = input as ISortedResultRequest;
                    if (sortInput != null)
                    {
                        if (!string.IsNullOrWhiteSpace(sortInput.Sorting))
                        {
                            List<string> strNames = sortInput.Sorting.ToDelimitedList<string>(" ");
                            sortName = (strNames.Count > 0) ? strNames[0] : null;
                            isDesc = sortInput.Sorting.IndexOf("desc", StringComparison.OrdinalIgnoreCase) > 0;
                        }
                    }
                }

    这样我们或者SortName,以及是否降序的判断。

    然后根据获得分页信息,并调用业务类的接口函数获取对应记录,构建为分页所需的JSON对象返回。

                //构建分页对象
                var pagerInfo = new PagerInfo() { CurrenetPageIndex = currentPage, PageSize = pageSize };
                if (!string.IsNullOrWhiteSpace(sortName))
                {
                    list = baseBLL.FindWithPager(condition, pagerInfo, sortName, isDesc);
                }
                else
                {
                    list = baseBLL.FindWithPager(condition, pagerInfo);
                }
    
                if (list != null)
                {
                    foreach (var item in list)
                    {
                        ConvertDto(item);//对Dto部分内容进行转义
                    }
                }
    
                //返回常用分页对象
                var result = new PagedResultDto<T> { TotalCount = totalCount, Items = list };
                return result;

    其中 PagedResultDto 是一个标准的分页数据返回的对象,定义如下所示。

        [Serializable]
        public class PagedResultDto<T> : ListResultDto<T>, IPagedResult<T>
        {
            /// <summary>
            /// Total count of Items.
            /// </summary>
            public int TotalCount { get; set; }
        [Serializable]
        public class ListResultDto<T> : IListResult<T>
        {
            /// <summary>
            /// List of items.
            /// </summary>
            public IReadOnlyList<T> Items
            {
                get { return _items ?? (_items = new List<T>()); }
                set { _items = value; }
            }
            private IReadOnlyList<T> _items;

    最后返回的结果集合类似如下所示:

    展开单条记录明细如下所示。

    这个对象使用了Camel样式的属性处理,所以返回的属性全部是Camel的格式。

        /// <summary>
        /// 统一处理Json的格式化信息
        /// </summary>
        public static class JsonFomatterHelper
        {
            /// <summary>
            /// 获取JSON的格式化信息
            /// </summary>
            /// <returns></returns>
            public static JsonMediaTypeFormatter GetFormatter()
            {
                var formatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
                formatter.SerializerSettings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                    DateFormatHandling = DateFormatHandling.IsoDateFormat,
                    DateFormatString = "yyyy-MM-dd HH:mm:ss",
                };
                return formatter;
            }
        }

    关于统一结果返回的封装处理,这里采用了WrapResultAttribute进行处理,详细可以参考我的随笔《利用过滤器Filter和特性Attribute实现对Web API返回结果的封装和统一异常处理》进行详细了解。

                // 重新封装回传格式
                actionExecutedContext.Response = new HttpResponseMessage(statusCode)
                {
                    Content = new ObjectContent<AjaxResponse>(
                       new AjaxResponse(content), JsonFomatterHelper.GetFormatter())
                };
    主要研究技术:代码生成工具、会员管理系统、客户关系管理软件、病人资料管理软件、Visio二次开发、酒店管理系统、仓库管理系统等共享软件开发
    专注于Winform开发框架/混合式开发框架Web开发框架Bootstrap开发框架微信门户开发框架的研究及应用
      转载请注明出处:
    撰写人:伍华聪  http://www.iqidi.com 
        
  • 相关阅读:
    从Hello World说起(Dart)到“几乎所有东西都是Widget”小部件。
    C#开发者工具网
    sqlitestudio
    jstat命令 Java Virtual Machine Statistics Monitoring Tool
    ProxyPass与ProxyPassReverse及ProxyPassMatch的概述
    IBM MQ介绍
    sun misc unsafe类的使用
    Android Webview实现文件下载功能
    使用OpenSSL生成私钥 Private Key 以及根据Private Key创建证书
    阿里巴巴的面试
  • 原文地址:https://www.cnblogs.com/wuhuacong/p/14675938.html
Copyright © 2020-2023  润新知