应用程序框架实战二十六:查询对象


  信息系统的查询需求千变万化,在仓储中为每个查询需求创建一个特殊方法,将导致大量乏味而臃肿的接口。

  一种更加可行的办法是,在应用层服务中描述查询需求,并通过仓储执行查询。

  为了能够更好的描述查询需求,可以将查询功能从仓储中抽取出来,专门创建一个查询对象。

  查询最复杂的部分是条件过滤,这也是查询对象的主要职责。查询对象可以认为是规约模式的一个变种,允许查询对象动态创建查询条件。

  在Util.Domains项目Repositories目录中,创建查询对象基接口IQueryBase,代码如下。

using System; using System.Linq.Expressions; namespace Util.Domains.Repositories { /// <summary>
    /// 查询对象 /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    public interface IQueryBase<TEntity> : IPager where TEntity : class, IAggregateRoot { /// <summary>
        /// 获取谓词 /// </summary>
        Expression<Func<TEntity, bool>> GetPredicate(); /// <summary>
        /// 获取排序 /// </summary>
        string GetOrderBy(); } }

  IQueryBase接口主要用来支持将查询对象传入仓储中。

  在仓储接口IRepository中增加两个方法,代码如下。

        /// <summary>
        /// 查询 /// </summary>
        /// <param name="query">查询对象</param>
        IQueryable<TEntity> Query( IQueryBase<TEntity> query ); /// <summary>
        /// 分页查询 /// </summary>
        /// <param name="query">查询对象</param>
        PagerList<TEntity> PagerQuery( IQueryBase<TEntity> query );

  在仓储类Repository中实现这两个方法,代码如下。

        /// <summary>
        /// 查询 /// </summary>
        /// <param name="query">查询对象</param>
        public IQueryable<TEntity> Query( IQueryBase<TEntity> query ) { return FilterBy( Find(), query ); } /// <summary>
        /// 过滤 /// </summary>
        protected IQueryable<TEntity> FilterBy( IQueryable<TEntity> queryable, IQueryBase<TEntity> query ) { var predicate = query.GetPredicate(); if ( predicate == null ) return queryable; return queryable.Where( predicate ); } /// <summary>
        /// 分页查询 /// </summary>
        /// <param name="query">查询对象</param>
        public virtual PagerList<TEntity> PagerQuery( IQueryBase<TEntity> query ) { return Query( query ).PagerResult( query ); }

  以上代码完成了将查询对象传入仓储并获取结果,下面开始实现查询对象。

  在Util.Datas项目Queries目录中,创建IQuery接口,代码如下。

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Util.Domains; using Util.Domains.Repositories; namespace Util.Datas.Queries { /// <summary>
    /// 查询对象 /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <typeparam name="TKey">实体标识类型</typeparam>
    public interface IQuery<TEntity, TKey> : IQueryBase<TEntity> where TEntity : class,IAggregateRoot<TKey> { /// <summary>
        /// 添加谓词,仅能添加一个条件,如果参数值为空,则忽略该条件 /// </summary>
        /// <param name="predicate">谓词</param>
        /// <param name="isOr">是否使用Or连接</param>
        IQuery<TEntity, TKey> Filter( Expression<Func<TEntity, bool>> predicate, bool isOr = false ); /// <summary>
        /// 过滤条件 /// </summary>
        /// <param name="propertyName">属性名</param>
        /// <param name="value"></param>
        /// <param name="operator">运算符</param>
        IQuery<TEntity,TKey> Filter( string propertyName, object value, Operator @operator = Operator.Equal ); /// <summary>
        /// 添加查询条件 /// </summary>
        /// <param name="criteria">查询条件</param>
        IQuery<TEntity,TKey> Filter( ICriteria<TEntity> criteria ); /// <summary>
        /// 过滤int数值段 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        IQuery<TEntity,TKey> FilterInt<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, int? min,int? max ); /// <summary>
        /// 过滤double数值段 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        IQuery<TEntity,TKey> FilterDouble<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, double? min, double? max ); /// <summary>
        /// 过滤日期段,不包含时间 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        IQuery<TEntity,TKey> FilterDate<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, DateTime? min, DateTime? max ); /// <summary>
        /// 过滤日期时间段,包含时间 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        IQuery<TEntity,TKey> FilterDateTime<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, DateTime? min, DateTime? max ); /// <summary>
        /// 过滤decimal数值段 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        IQuery<TEntity,TKey> FilterDecimal<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, decimal? min, decimal? max ); /// <summary>
        /// 与连接,将传入的查询条件合并到当前对象 /// </summary>
        /// <param name="query">查询对象</param>
        IQuery<TEntity,TKey> And( IQuery<TEntity,TKey> query ); /// <summary>
        /// 与连接,将传入的查询条件合并到当前对象 /// </summary>
        /// <param name="predicate">谓词</param>
        IQuery<TEntity,TKey> And( Expression<Func<TEntity, bool>> predicate ); /// <summary>
        /// 或连接,将传入的查询条件合并到当前对象 /// </summary>
        /// <param name="query">查询对象</param>
        IQuery<TEntity,TKey> Or( IQuery<TEntity,TKey> query ); /// <summary>
        /// 或连接,将传入的查询条件合并到当前对象 /// </summary>
        /// <param name="predicate">谓词</param>
        IQuery<TEntity,TKey> Or( Expression<Func<TEntity, bool>> predicate ); /// <summary>
        /// 添加排序,支持多次调用OrderBy创建多级排序 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="expression">属性表达式</param>
        /// <param name="desc">是否降序</param>
        IQuery<TEntity,TKey> OrderBy<TProperty>( Expression<Func<TEntity, TProperty>> expression, bool desc = false ); /// <summary>
        /// 添加排序,支持多次调用OrderBy创建多级排序 /// </summary>
        /// <param name="propertyName">排序属性</param>
        /// <param name="desc">是否降序</param>
        IQuery<TEntity,TKey> OrderBy( string propertyName, bool desc = false ); /// <summary>
        /// 获取列表 /// </summary>
        /// <param name="queryable">数据源</param>
        List<TEntity> GetList( IQueryable<TEntity> queryable ); /// <summary>
        /// 获取分页列表 /// </summary>
        /// <param name="queryable">数据源</param>
        PagerList<TEntity> GetPagerList( IQueryable<TEntity> queryable ); } }

  查询对象中定义的过滤方法默认都是以And方式连接,所以需要增加专门的Or连接方法。当查询需求比较复杂时,可以创建多个查询对象进行合并,从而创建更为复杂的查询条件。

  为了使用方便,查询对象本身还提供了获取数据的方法,需要传入IQueryable 对象,以便执行实际的查询操作。

  在Util.Datas项目Queries目录中,创建查询对象实现类Query,代码如下。

using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Util.Datas.Queries.Criterias; using Util.Datas.Queries.OrderBys; using Util.Domains; using Util.Domains.Repositories; namespace Util.Datas.Queries { /// <summary>
    /// 查询对象 /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>
    /// <typeparam name="TKey">实体标识类型</typeparam>
    public class Query<TEntity, TKey> : Pager, IQuery<TEntity, TKey> where TEntity : class ,IAggregateRoot<TKey> { #region 构造方法

        /// <summary>
        /// 初始化查询对象 /// </summary>
        public Query() { OrderBuilder = new OrderByBuilder(); } /// <summary>
        /// 初始化查询对象 /// </summary>
        /// <param name="pager">分页对象</param>
        public Query( IPager pager ) : this() { Page = pager.Page; PageSize = pager.PageSize; TotalCount = pager.TotalCount; OrderBy( pager.Order ); } #endregion

        #region 属性

        /// <summary>
        /// 查询条件 /// </summary>
        private ICriteria<TEntity> Criteria { get; set; } /// <summary>
        /// 排序生成器 /// </summary>
        private OrderByBuilder OrderBuilder { get; set; } #endregion

        #region GetPredicate(获取谓词)

        /// <summary>
        /// 获取谓词 /// </summary>
        public Expression<Func<TEntity, bool>> GetPredicate() { if ( Criteria == null ) return null; return Criteria.GetPredicate(); } #endregion

        #region GetOrderBy(获取排序)

        /// <summary>
        /// 获取排序 /// </summary>
        public string GetOrderBy() { Order = OrderBuilder.Generate(); if ( string.IsNullOrWhiteSpace( Order ) ) Order = "Id desc"; return Order; } #endregion

        #region 过滤条件

        /// <summary>
        /// 添加谓词,仅能添加一个条件,如果参数值为空,则忽略该条件 /// </summary>
        /// <param name="predicate">谓词</param>
        /// <param name="isOr">是否使用Or连接</param>
        public IQuery<TEntity, TKey> Filter( Expression<Func<TEntity, bool>> predicate,bool isOr = false ) { predicate = QueryHelper.ValidatePredicate( predicate ); if ( predicate == null ) return this; if ( isOr ) Or( predicate ); else And( predicate ); return this; } /// <summary>
        /// 过滤条件 /// </summary>
        /// <param name="propertyName">属性名</param>
        /// <param name="value"></param>
        /// <param name="operator">运算符</param>
        public IQuery<TEntity, TKey> Filter( string propertyName, object value, Operator @operator = Operator.Equal ) { return Filter( Lambda.ParsePredicate<TEntity>( propertyName, value, @operator ) ); } /// <summary>
        /// 添加查询条件 /// </summary>
        /// <param name="criteria">查询条件</param>
        public IQuery<TEntity, TKey> Filter( ICriteria<TEntity> criteria ) { And( criteria.GetPredicate() ); return this; } /// <summary>
        /// 过滤int数值段 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public IQuery<TEntity, TKey> FilterInt<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, int? min, int? max ) { return Filter( new IntSegmentCriteria<TEntity, TProperty>( propertyExpression, min, max ) ); } /// <summary>
        /// 过滤double数值段 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public IQuery<TEntity, TKey> FilterDouble<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, double? min, double? max ) { return Filter( new DoubleSegmentCriteria<TEntity, TProperty>( propertyExpression, min, max ) ); } /// <summary>
        /// 过滤日期段,不包含时间 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public IQuery<TEntity, TKey> FilterDate<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, DateTime? min, DateTime? max ) { return Filter( new DateSegmentCriteria<TEntity, TProperty>( propertyExpression, min, max ) ); } /// <summary>
        /// 过滤日期时间段,包含时间 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public IQuery<TEntity, TKey> FilterDateTime<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, DateTime? min, DateTime? max ) { return Filter( new DateTimeSegmentCriteria<TEntity, TProperty>( propertyExpression, min, max ) ); } /// <summary>
        /// 过滤decimal数值段 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="propertyExpression">属性表达式,范例:t => t.Age</param>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        public IQuery<TEntity, TKey> FilterDecimal<TProperty>( Expression<Func<TEntity, TProperty>> propertyExpression, decimal? min, decimal? max ) { return Filter( new DecimalSegmentCriteria<TEntity, TProperty>( propertyExpression, min, max ) ); } #endregion

        #region 连接

        /// <summary>
        /// 与连接,将传入的查询条件合并到当前对象 /// </summary>
        /// <param name="query">查询对象</param>
        public IQuery<TEntity, TKey> And( IQuery<TEntity, TKey> query ) { return And( query.GetPredicate() ); } /// <summary>
        /// 与连接,将传入的查询条件合并到当前对象 /// </summary>
        /// <param name="predicate">谓词</param>
        public IQuery<TEntity, TKey> And( Expression<Func<TEntity, bool>> predicate ) { if ( Criteria == null ) { Criteria = new Criteria<TEntity>( predicate ); return this; } Criteria = new AndCriteria<TEntity>( Criteria.GetPredicate(), predicate ); return this; } /// <summary>
        /// 或连接,将传入的查询条件合并到当前对象 /// </summary>
        /// <param name="query">查询对象</param>
        public IQuery<TEntity, TKey> Or( IQuery<TEntity, TKey> query ) { return Or( query.GetPredicate() ); } /// <summary>
        /// 或连接,将传入的查询条件合并到当前对象 /// </summary>
        /// <param name="predicate">谓词</param>
        public IQuery<TEntity, TKey> Or( Expression<Func<TEntity, bool>> predicate ) { if ( Criteria == null ) { Criteria = new Criteria<TEntity>( predicate ); return this; } Criteria = new OrCriteria<TEntity>( Criteria.GetPredicate(), predicate ); return this; } #endregion

        #region OrderBy(排序)

        /// <summary>
        /// 添加排序,支持多次调用OrderBy创建多级排序 /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="expression">属性表达式</param>
        /// <param name="desc">是否降序</param>
        public IQuery<TEntity, TKey> OrderBy<TProperty>( Expression<Func<TEntity, TProperty>> expression, bool desc = false ) { return OrderBy( Lambda.GetName( expression ), desc ); } /// <summary>
        /// 添加排序,支持多次调用OrderBy创建多级排序 /// </summary>
        /// <param name="propertyName">排序属性</param>
        /// <param name="desc">是否降序</param>
        public IQuery<TEntity, TKey> OrderBy( string propertyName, bool desc = false ) { OrderBuilder.Add( propertyName, desc ); GetOrderBy(); return this; } #endregion

        #region Clear(清理)

        /// <summary>
        /// 清理 /// </summary>
        public void Clear() { Criteria = null; OrderBuilder = new OrderByBuilder(); } #endregion

        #region GetList(获取列表)

        /// <summary>
        /// 获取列表 /// </summary>
        /// <param name="queryable">数据源</param>
        public List<TEntity> GetList( IQueryable<TEntity> queryable ) { return Execute( queryable ).OrderBy( Order ).ToList(); } /// <summary>
        /// 执行过滤和分页 /// </summary>
        private IQueryable<TEntity> Execute( IQueryable<TEntity> queryable ) { queryable.CheckNull( "queryable" ); queryable = FilterBy( queryable ); GetOrderBy(); return queryable; } /// <summary>
        /// 过滤 /// </summary>
        private IQueryable<TEntity> FilterBy( IQueryable<TEntity> queryable ) { if ( Criteria == null ) return queryable; return queryable.Where( Criteria.GetPredicate() ); } #endregion

        #region GetPagerList(获取分页列表)

        /// <summary>
        /// 获取分页列表 /// </summary>
        /// <param name="queryable">数据源</param>
        public PagerList<TEntity> GetPagerList( IQueryable<TEntity> queryable ) { return Execute( queryable ).PagerResult( this ); } #endregion } }

  应用层服务可以这样查询。

        public PagerList<ApplicationDto> Query( ApplicationQuery query ) { return new Query<Application>(query) .Filter( t => t.Code == query.Code ) .Filter( t => t.Name.Contains( query.Name ) ) .Filter( t => t.Enabled == query.Enabled ) .FilterDate( t => t.CreateTime, query.BeginCreateTime, query.EndCreateTime ) .GetPagerList( Repository.Find() ).Convert( t => t.ToDto() ); }

        public PagerList<ApplicationDto> Query2( ApplicationQuery query ) { var queryObject = new Query<Application>( query ) .Filter( t => t.Code == query.Code ) .Filter( t => t.Name.Contains( query.Name ) ) .Filter( t => t.Enabled == query.Enabled ) .FilterDate( t => t.CreateTime, query.BeginCreateTime, query.EndCreateTime ); return Repository.PagerQuery( queryObject ).Convert( t => t.ToDto() ); }

 

  .Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。

  谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/xiadao521/


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM