复杂的数据查询是web系统中很重要的一部分。如果数据访问代码构建在一个Dao对象或者repository对象中其实也是可行的。如果把复杂的数据查询抽离出来单独建模,
让Dao对象和repository对象只留下基本的数据访问访问,不就可行实现更高阶的责任分离了吗。(以下讲解以本文附带的代码为例)
查询对象模式对象模式正好可以用来解决这个问题。分来复杂查询,我们需要对查询建模。查询的的目的就是为了执行一段代码,以返回结果
我们可定义这样的接口:
namespace QueryObject.Core.Data.Query
{
/// <summary>
/// Description of IQuery.
/// </summary>
public interface IQuery
{
}
public interface IQuery<TResult> : IQuery
{
TResult Execute();
}
}
接口中只有一个方法,任何实现该接口的对象都是一个查询对象。比如我们想提供一个产品的复杂查询,很明显的我们只需要构造一个实现IQuery<TResult>接口的对象就可以了,
ProductSearch类直接实现查询接口也是可以的,但是为了比如面向接口编程或者提供一种契约什么的我们先定义个IProductSearch接口来实现IQuery<TResult>,而ProductSearch实现IProductSearch接口就可以了:
namespace QueryObject.Core.Data.Query
{
/// <summary>
/// Description of IProductSearch.
/// </summary>
public interface IProductSearch : IQuery<IEnumerable<Product>>
{
string Name { get; set;}
string Description { get; set;}
decimal? MinimumPrice {get; set;}
decimal? MaximumPrice { get; set;}
ProductSearchSort Sort { get; set;}
}
public enum ProductSearchSort
{
PriceAsc,
PriceDesc,
Name
}
}
代码中象征性的提供了两种方式实现该接口,一个是用查询字符串实现的ProductSearch, 它的继承体系是SqlBase, SqlQueryBase, SqlCmdQueryBase, ProductSearch
另外一个是打算用存储过程实现的ProcProductSearch,它的继承体系是SqlBase, SqlQueryBase, SqlProcQueryBase, ProcProductSearch
当然用ORM工具来实现是更方便的
使用中可以根据各种各样的查询需要创建针对每个查询的的查询对象,以及对应的分页查询对象
Dao对象或者repository对象要想使用查询对象要想方法获得查案对象,为了方便,
我们再定义一个查询对象工厂的接口,该接口的实现者可以方便的返回需要的查询对象:
namespace QueryObject.Core.Data.Query
{
/// <summary>
/// Description of IQueryFactory
/// </summary>
public interface IQueryFactory
{
TQuery CreateQuery<TQuery>() where TQuery : IQuery;
}
}
至于如何实现该接口的方法很多,代码提供了一个简单实现是位于QueryObject.Core.Data.Imp命名空间的QueryFactory
到此为止,我们有了查询对象以及方便定位查询对象对象的查询对象工厂,下一步就是创建repository类来使用查询对象。定义一个基本接口:
IRepository<T>, 代码中为了让每个实现该接口的repository类都向外提供复杂查询,IRepository<T>先继承了IQueryFactory接口。
namespace QueryObject.Core.Data
{
/// <summary>
/// Description of IRepository.
/// </summary>
public interface IRepository<T> : IQueryFactory where T : Entity
{
//基本操作
}
}
现在的效果是每个repository也是一个queryFactory对象,而实际上repository对象持有一个单独实现IQueryFactory接口的对象的 引用,repository对象也只有包装了下对
CreateQuery<TQuery>() 方法的调用而已。
代码有个对IRepository接口的实现ProductRepository. 它的继承体系是SqlBase,SqlRepository, ProductRepository。
到此为止,基本代码结构已构建完毕。那么如何调用呢?测试代码总有一段,
IDbConnection conn = new SqlConnection(@"Server=.\SQLExpress;Database=Test; Trusted_Connection=SSPI");
IQueryFactory queryFactory = new QueryFactory(conn);
ProductRepository target = new ProductRepository(conn, queryFactory);
var query = target.CreateQuery<ProductSearch>();
query.Name = "apple";
var result = query.Execute();
写的比较简陋,也不知道有没说清楚,更不知道是不是能让人看懂。不过如何能对照源码看应该能看懂了,哈哈,下代码吧