企业应用架构模式——QueryObject模式
2012-12-29 13:29
302 查看
场景
比如我们有个Employee实体,属性有EmployeeID(雇员id)、NationalIDNumber(雇员标志号,如身份证)、ManagerID(雇员上司id)、Title(职位)、MaritalStatus(婚姻状态)、Gender(性别)、HireDate(雇佣日期)、SalariedFlag(工作性质,计时或月薪)。我们写数据库层时经常会遇到这样的需求:
查询标志号为"001”的雇员
查询计时或月薪的雇员
可以看出只要我们有通过对象属性来查询对象,就要在相应的数据层增加对应的Findxxx方法,不过这只是单一的查询,如果存在组合条件的查询,Employee仓储中会充斥大量的检索方法。
QueryObject模式
QueryObject(查询对象)是一个解释器,也就是说,他是由多个对象组成的结构,该结构可以自身转化为一个sql查询。可以通过引用类的和属性来创建对应数据库表和列的查询。
查询对象的好处
1、完全将底层数据库的查询语言抽象出来,因此将数据库持久化和检索的基础设施关注点从业务层中分离出来。
2、对于多个数据库,通过设计查询对象,根据运行的数据库来产生不同的sql,屏蔽了各种不同sql语法中的差别。
3、消除对数据库的查询冗余,如果在先前的会话中运行过相同的查询,可以使用查询对象从标志映射中选取对象。
QueryObject模型类图
实现QueryObject模式
首先创建一个枚举CriteriaOperator用来处理查询条件的映射
[code]{
[/code]
创建查询过滤器的类Criterion
[code]///查询过滤器
[/code]
创建一个用于表示排序属性的类OrderByClause
[code]{
[/code]
创建另一个枚举QueryOperator,用来表示条件的连字符and或者or
[code]{
[/code]
有时候复杂的查询对象难以构建,我们会通过存储过程或视图来处理此种情况,需要构建一个枚举QueryName用来指示是存储过程(视图)还是构建动态的sql语句
[code]{
[/code]
最后创建Query类,用来组合查询条件(Criterion)、查询条件连字符(QueryOperator),排序(OrderByClause)
[code]{
[/code]
使用QueryObject模式
仓储层(Repository)接口
[code]{
[/code]
创建一个翻译器,将查询对象翻译成sql语句
[code]{
[/code]
仓储实现层
[code]{
[/code]
控制台调用
[code]{
[/code]
源代码下载
比如我们有个Employee实体,属性有EmployeeID(雇员id)、NationalIDNumber(雇员标志号,如身份证)、ManagerID(雇员上司id)、Title(职位)、MaritalStatus(婚姻状态)、Gender(性别)、HireDate(雇佣日期)、SalariedFlag(工作性质,计时或月薪)。我们写数据库层时经常会遇到这样的需求:
查询标志号为"001”的雇员
publicclassEmployeeRepository:IRepository<Employee> { publicEmployeeFind(objectid) {} }
查询计时或月薪的雇员
publicclassEmployeeRepository:IRepository<Employee> { publicIEnumerable<Employee>FindSalariedEmployee(SalariedFlagsalariedFlag) {} }
可以看出只要我们有通过对象属性来查询对象,就要在相应的数据层增加对应的Findxxx方法,不过这只是单一的查询,如果存在组合条件的查询,Employee仓储中会充斥大量的检索方法。
QueryObject模式
QueryObject(查询对象)是一个解释器,也就是说,他是由多个对象组成的结构,该结构可以自身转化为一个sql查询。可以通过引用类的和属性来创建对应数据库表和列的查询。
查询对象的好处
1、完全将底层数据库的查询语言抽象出来,因此将数据库持久化和检索的基础设施关注点从业务层中分离出来。
2、对于多个数据库,通过设计查询对象,根据运行的数据库来产生不同的sql,屏蔽了各种不同sql语法中的差别。
3、消除对数据库的查询冗余,如果在先前的会话中运行过相同的查询,可以使用查询对象从标志映射中选取对象。
QueryObject模型类图
实现QueryObject模式
首先创建一个枚举CriteriaOperator用来处理查询条件的映射
publicenumCriteriaOperator
[code]{
Equal,//=
LessThanOrEqual,//<=
NotApplicable,//≠
LessThan,//<
GreaterThan,//>
GreaterThanOrEqual,//>=
Like//%
}
[/code]
创建查询过滤器的类Criterion
///<summary>
[code]///查询过滤器
///</summary>
publicclassCriterion
{
privatestring_propertyName;//实体属性
privateobject_value;//进行比较的值
privateCriteriaOperator_criteriaOperator;//比较操作符
publicCriterion(stringpropertyName,objectvalue,CriteriaOperatorcriteriaOperator)
{
_propertyName=propertyName;
_value=value;
_criteriaOperator=criteriaOperator;
}
publicstringPropertyName
{
get{return_propertyName;}
}
publicobjectValue
{
get{return_value;}
}
publicCriteriaOperatorCriteriaOperator
{
get{return_criteriaOperator;}
}
}
[/code]
创建一个用于表示排序属性的类OrderByClause
publicclassOrderByClause
[code]{
publicstringPropertyName{get;set;}//属性名对应数据库表的列名
publicboolDesc{get;set;}//descorasc
}
[/code]
创建另一个枚举QueryOperator,用来表示条件的连字符and或者or
publicenumQueryOperator
[code]{
And,
Or
}
[/code]
有时候复杂的查询对象难以构建,我们会通过存储过程或视图来处理此种情况,需要构建一个枚举QueryName用来指示是存储过程(视图)还是构建动态的sql语句
publicenumQueryName
[code]{
Dynamic=0,//动态创建
RetrieveOrdersUsingAComplexQuery=1//使用已经创建好了的存储过程、视图、特别是查询比较复杂时使用存储过程
}
[/code]
最后创建Query类,用来组合查询条件(Criterion)、查询条件连字符(QueryOperator),排序(OrderByClause)
publicclassQuery
[code]{
privateQueryName_name;
privateIList<Criterion>_criteria;//查询条件
publicQuery():this(QueryName.Dynamic,newList<Criterion>())
{}
publicQuery(QueryNamename,IList<Criterion>criteria)
{
_name=name;
_criteria=criteria;
}
publicQueryNameName
{
get{return_name;}
}
///<summary>
///判断是存储过程还是动态sql
///</summary>
///<returns></returns>
publicboolIsNamedQuery()
{
returnName!=QueryName.Dynamic;
}
publicIEnumerable<Criterion>Criteria
{
get{return_criteria;}
}
publicvoidAdd(Criterioncriterion)
{
if(!IsNamedQuery())
{
_criteria.Add(criterion);
}
else
{
thrownewApplicationException("Youcannotaddadditionalcriteriatonamedqueries");
}
}
//查询条件连字符
publicQueryOperatorQueryOperator
{
get;
set;
}
//排序列
publicOrderByClauseOrderByProperty
{
get;
set;
}
}
[/code]
使用QueryObject模式
仓储层(Repository)接口
publicinterfaceIRepository<T>
[code]{
intAdd(Tentity);
intSave(Tentity);
voidDelete(Tentity);
TFind(objectid);
TFind(Queryquery);
IEnumerable<T>FindBy(Queryquery);
IEnumerable<T>FindBy(Queryquery,intpageSize,intpageCount);
}
[/code]
创建一个翻译器,将查询对象翻译成sql语句
publicstaticclassAdmissionTicketOrderQueryTranslator
[code]{
privatestaticreadonlystringbaseSelectQuery="SELECT*FROMAdmissionTicketOrder";
publicstaticvoidTranslateInfo(thisQueryquery,SqlCommandcmd)
{
if(query.IsNamedQuery())
{
cmd.CommandType=CommandType.StoredProcedure;
cmd.CommandText=query.Name.ToString();
foreach(Criterioncriteriainquery.Criteria)
{
cmd.Parameters.Add(newSqlParameter("@"+criteria.PropertyName,criteria.Value));
}
}
else
{
StringBuildersqlQuery=newStringBuilder();
sqlQuery.Append(baseSelectQuery);
bool_isNotfirstFilterClause=false;
if(query.Criteria.Count()>0)
{
sqlQuery.Append("WHERE");
}
foreach(Criterioncriterioninquery.Criteria)
{
if(_isNotfirstFilterClause)
{
sqlQuery.Append(GetQueryOperator(query));
}
sqlQuery.Append(AddFilterClauseFrom(criterion));
cmd.Parameters.Add(newSqlParameter("@"+criterion.PropertyName,criterion.Value));
_isNotfirstFilterClause=true;
}
sqlQuery.Append(GenerateOrderByClauseFrom(query.OrderByProperty));
cmd.CommandType=CommandType.Text;
cmd.CommandText=sqlQuery.ToString();
}
}
privatestaticstringGenerateOrderByClauseFrom(OrderByClauseorderByClause)
{
returnString.Format("ORDERBY{0}{1}",
FindTableColumnFor(orderByClause.PropertyName),orderByClause.Desc?"DESC":"ASC");
}
///<summary>
///
///</summary>
///<paramname="query"></param>
///<returns></returns>
privatestaticstringGetQueryOperator(Queryquery)
{
if(query.QueryOperator==QueryOperator.And)
{
return"AND";
}
else
{
return"OR";
}
}
privatestaticstringAddFilterClauseFrom(Criterioncriterion)
{
returnstring.Format("{0}{1}@{2}",FindTableColumnFor(criterion.PropertyName),FindSQLOperatorFor(criterion.CriteriaOperator),criterion.PropertyName);
}
privatestaticstringFindSQLOperatorFor(CriteriaOperatorcriteriaOperator)
{
switch(criteriaOperator)
{
caseCriteriaOperator.Equal:
return"=";
caseCriteriaOperator.LessThanOrEqual:
return"<=";
caseCriteriaOperator.NotApplicable:
return"<>";
caseCriteriaOperator.LessThan:
return"<";
caseCriteriaOperator.GreaterThan:
return">";
caseCriteriaOperator.GreaterThanOrEqual:
return">=";
default:
thrownewApplicationException("Nooperatordefined.");
}
}
privatestaticstringFindTableColumnFor(stringpropertyName)
{
switch(propertyName)
{
case"ID":
return"ID";
case"OrderID":
return"OrderID";
case"TicketId":
return"TicketId";
case"OrderUserName":
return"OrderUserName";
case"OrderUserSex":
return"OrderUserSex";
case"OrderUserPhone":
return"OrderUserPhone";
case"ProviderContactName":
return"ProviderContactName";
case"TicetUseDateTime":
return"TicetUseDateTime";
case"SalePrice":
return"SalePrice";
case"BuyPrice":
return"BuyPrice";
case"BuyAmount":
return"BuyAmount";
case"TicketType":
return"TicketType";
default:
thrownewApplicationException("Nocolumndefinedforthisproperty.");
}
}
}
[/code]
仓储实现层
publicclassAdmissionTicketOrderRepository:IRepository<AdmissionTicketOrder>
[code]{
privateSqlHelper_sqlHelper;
publicAdmissionTicketOrderRepository(SqlHelpersqlHelper)
{
_sqlHelper=sqlHelper;
}
privatestaticreadonlystringinsertOrderExtendSql="sp_InsertOrUpdateAdmissionTicketOrder";
publicintAdd(AdmissionTicketOrderentity)
{
using(varcmd=_sqlHelper.PrepareStoredSqlCommand(insertOrderExtendSql))
{
cmd.AddParam("@ID",entity.ID);
cmd.AddParam("@OrderID",entity.OrderID);
cmd.AddParam("@TicketId",entity.TicketId);
cmd.AddParam("@OrderUserName",entity.OrderUserName);
cmd.AddParam("@OrderUserSex",entity.OrderUserSex);
cmd.AddParam("@OrderUserPhone",entity.OrderUserPhone);
cmd.AddParam("@ProviderContactName",entity.ProviderContactName);
cmd.AddParam("@ProviderContactPhone",entity.ProviderContactPhone);
cmd.AddParam("@TicetUseDateTime",entity.TicetUseDateTime);
cmd.AddParam("@IsNeed",entity.IsNeed);
cmd.AddParam("@BillAddress",entity.BillAddress);
cmd.AddParam("@BuyPrice",entity.BuyPrice);
cmd.AddParam("@SalePrice",entity.SalePrice);
cmd.AddParam("@BuyAmount",entity.BuyAmount);
cmd.AddParam("@GetTicketAddress",entity.GetTicketAddress);
cmd.AddParam("@TicketType",entity.TicketType);
varparm=cmd.AddReturnValueParameter("ReturnValue");
cmd.ExecuteNonQuery();
return(int)parm.Value;
}
}
publicintSave(AdmissionTicketOrderentity)
{
returnAdd(entity);
}
privatestaticreadonlystringdeleteOrder="DELETEAdmissionTicketOrderWHEREID=@Id";
publicvoidDelete(AdmissionTicketOrderentity)
{
using(varcmd=_sqlHelper.PrepareTextSqlCommand(deleteOrder))
{
cmd.AddParam("@Id",entity.ID);
cmd.ExecuteNonQuery();
}
}
privatestaticreadonlystringselectOrder="SELECT*FROMAdmissionTicketOrderWHEREID=@Id";
publicAdmissionTicketOrderFind(objectid)
{
using(varcmd=_sqlHelper.PrepareTextSqlCommand(selectOrder))
{
cmd.AddParam("@Id",id);
using(varreader=cmd.ExecuteReader())
{
if(reader.Read())
{
return(newAdmissionTicketOrder
{
Id=reader.GetValue<int>("Id"),
OrderID=reader.GetValue<int>("OrderID"),
TicketId=reader.GetValue<int>("TicketId"),
OrderUserName=reader.GetValue<string>("OrderUserName"),
OrderUserSex=reader.GetValue<int>("OrderUserSex"),
OrderUserPhone=reader.GetValue<string>("OrderUserPhone"),
ProviderContactName=reader.GetValue<string>("ProviderContactName"),
ProviderContactPhone=reader.GetValue<string>("ProviderContactPhone"),
TicetUseDateTime=reader.GetValue<DateTime>("TicetUseDateTime"),
IsNeed=reader.GetValue<bool>("IsNeed"),
BillAddress=reader.GetValue<string>("BillAddress"),
SalePrice=reader.GetValue<decimal>("SalePrice"),
BuyPrice=reader.GetValue<decimal>("BuyPrice"),
BuyAmount=reader.GetValue<decimal>("BuyAmount"),
GetTicketAddress=reader.GetValue<string>("GetTicketAddress"),
TicketType=reader.GetValue<string>("TicketType")
});
}
returnnull;
}
}
}
publicAdmissionTicketOrderFind(Queryquery)
{
SqlCommandcmd=_sqlHelper.PrepareSqlCommand();
query.TranslateInfo(cmd);
using(varreader=cmd.ExecuteReader())
{
if(reader.Read())
{
return(newAdmissionTicketOrder
{
Id=reader.GetValue<int>("Id"),
OrderID=reader.GetValue<int>("OrderID"),
TicketId=reader.GetValue<int>("TicketId"),
OrderUserName=reader.GetValue<string>("OrderUserName"),
OrderUserSex=reader.GetValue<int>("OrderUserSex"),
OrderUserPhone=reader.GetValue<string>("OrderUserPhone"),
ProviderContactName=reader.GetValue<string>("ProviderContactName"),
ProviderContactPhone=reader.GetValue<string>("ProviderContactPhone"),
TicetUseDateTime=reader.GetValue<DateTime>("TicetUseDateTime"),
IsNeed=reader.GetValue<bool>("IsNeed"),
BillAddress=reader.GetValue<string>("BillAddress"),
SalePrice=reader.GetValue<decimal>("SalePrice"),
BuyPrice=reader.GetValue<decimal>("BuyPrice"),
BuyAmount=reader.GetValue<decimal>("BuyAmount"),
GetTicketAddress=reader.GetValue<string>("GetTicketAddress"),
TicketType=reader.GetValue<string>("TicketType")
});
}
returnnull;
}
}
publicIEnumerable<AdmissionTicketOrder>FindBy(Queryquery)
{
IList<AdmissionTicketOrder>admissionTicketOrders=newList<AdmissionTicketOrder>();
SqlCommandcmd=_sqlHelper.PrepareSqlCommand();
query.TranslateInfo(cmd);
using(SqlDataReaderreader=cmd.ExecuteReader())
{
while(reader.Read())
{
admissionTicketOrders.Add(
newAdmissionTicketOrder
{
Id=reader.GetValue<int>("Id"),
OrderID=reader.GetValue<int>("OrderID"),
TicketId=reader.GetValue<int>("TicketId"),
OrderUserName=reader.GetValue<string>("OrderUserName"),
OrderUserSex=reader.GetValue<int>("OrderUserSex"),
OrderUserPhone=reader.GetValue<string>("OrderUserPhone"),
ProviderContactName=reader.GetValue<string>("ProviderContactName"),
ProviderContactPhone=reader.GetValue<string>("ProviderContactPhone"),
TicetUseDateTime=reader.GetValue<DateTime>("TicetUseDateTime"),
IsNeed=reader.GetValue<bool>("IsNeed"),
BillAddress=reader.GetValue<string>("BillAddress"),
SalePrice=reader.GetValue<decimal>("SalePrice"),
BuyPrice=reader.GetValue<decimal>("BuyPrice"),
BuyAmount=reader.GetValue<decimal>("BuyAmount"),
GetTicketAddress=reader.GetValue<string>("GetTicketAddress"),
TicketType=reader.GetValue<string>("TicketType")
}
);
}
}
returnadmissionTicketOrders;
}
publicIEnumerable<AdmissionTicketOrder>FindBy(Queryquery,intpageSize,intpageCount)
{
returnFindBy(query).Skip(pageSize*pageCount).Take(pageCount);
}
}
[/code]
控制台调用
staticvoidMain(string[]args)
[code]{
using(varsqlHelper=newSqlHelper("ConnectionString"))
{
AdmissionTicketOrderRepositoryator=newAdmissionTicketOrderRepository(sqlHelper);
AdmissionTicketOrderato=ator.Find(2);
Queryquery=newQuery();
query.Add(newCriterion("SalePrice",100,CriteriaOperator.GreaterThan));
query.QueryOperator=QueryOperator.And;
query.Add(newCriterion("TicketType","单一票型",CriteriaOperator.Equal));
query.Add(newCriterion("BuyAmount",250,CriteriaOperator.LessThan));
query.QueryOperator=QueryOperator.And;
query.OrderByProperty=newOrderByClause{PropertyName="TicetUseDateTime",Desc=true};
List<AdmissionTicketOrder>list=ator.FindBy(query).ToList();
foreach(variteminlist)
{
Console.WriteLine("{0}{1}{2}{3}",item.ID,item.ProviderContactName,item.BuyPrice,item.SalePrice);
}
}
Console.Read();
}
[/code]
相关文章推荐
- 企业应用架构模式 Patterns of Enterprise Application Architecture
- 引言(企业应用架构模式)
- 企业应用架构模式--引言
- 企业应用架构模式--对象-关系行为模式(第11章)
- 企业应用架构模式电子版(PDF格式)下载
- 关于企业应用架构模式总体分析
- 企业应用架构模式 Martin Fowler著 - 读书笔记
- 软件开发大师谈企业应用架构模式
- 企业应用架构模式阅读笔记 - Martin Fowler
- 企业应用架构模式之标识映射
- 企业应用架构模式之延迟加载
- 总结 - 设计模式,企业应用架构模式,架构模式
- 企业应用架构模式--会话状态(第六章)
- 读-Martin Fowler-企业应用架构模式
- 企业应用架构模式笔记(引言)
- 企业架构应用模式笔记--第二章(组织领域逻辑)
- 企业应用架构模式之领域逻辑模式
- 读企业应用架构模式的一些疑惑
- 读<企业应用架构模式>
- 企业应用架构模式--web表现层