本文描述如何实现支持分页的应用协议.
1.实现步骤
(1)定义分页条件类
不同应用协议查询条件项可能不同,定义对应的查询条件类,该类从CPageCond派生.
CPageCond是分页条件类.
如:
class CStoreGoodsSaleQueryCond : public CPageCond {
public:
string store_id_; ///< 门店ID
string last_date_;///< 上日日期
unsigned int cmonth_; ///< 当前月份
double total_num_; ///< 合计总金额(符合条件记录的汇总金额)
public:
CStoreGoodsSaleQueryCond():cmonth_(0),total_num_(0) {
}
};
(2)按以下示例格式编写协议处理函数
本示例中的:
report_->query_goods_sale
执行具体的查询逻辑,对于简单的协议可直接在协议处理函数内完成.
CPagizeHelper为分页处理辅助类.
示例代码如下:
int CMPPlugin::OnQueryStoreGoodsSale((CWrappedMsg<> *in,vector<CWrappedMsg<> *> &out,DISPATCH_RESULT &or) {
CMsg *msg = in->msg;
CPagizeHelper ph;
ph.dbc_name_ = this->local_dbc_.c_str();
CStoreGoodsSaleQueryCond cond;
///< 从消息中获取分页信息(CPageCond部分)
ph.GetPageCond(msg,&cond);
///< 从消息中获取CStoreGoodsSaleQueryCond的其它条件项
...
///< 执行查询,返回结果保存在vData中
CAutoVector<CGoodsSale*> vData;
int result = report_->query_goods_sale(orgid,userno,&cond,vData);
CMsg *ans = new CMsg;
///< 把查询结果写入消息包
...
///< 写入分页结果信息
ph.PutPageResult(ans,&cond);
DO_RESP(ans,out);
return 0;
}
查询逻辑的示例代码如下:
int CReport::query_goods_sale(CQQ_ORGID orgid,CQQ_USERNO userserial,CStoreGoodsSaleQueryCond *cond,vector<CGoodsSale*> &v) {
...
///< 处理查询条件
if (!cond->store_id_.empty()) {
where_expr += LogMsg(" and store_id='%s'",cond->store_id_.c_str());
}
CPagizeHelper ph;
ph.dbc_name_ = ; ///< 设置数据库连接
///< 确定总记录数
if (cond->count_flag_) {
string sql = LogMsg("select count(*) from (select count(*) as cnt_num from %s where %s group by %s having sum(%s)<>0 ) a",tbl_name.c_str(),where_expr.c_str(),group_expr.c_str(),sum_fld.c_str());
int ret = ph.GetCount(sql.c_str(),cond);
if (ret!=1)///< 检查是否有数据
return ret==1 ? -1 : 0;
}
string csql = LogMsg("select a.barcode from %s where %s group by %s having sum(%s)<>0",tbl_name.c_str(),where_expr.c_str(),group_expr.c_str(),sum_fld.c_str());
string tsql = LogMsg("select %s from %s,(%s) c where a.barcode=c.barcode and %s group by %s order by %s desc,a.barcode desc",fld_list.c_str(),tbl_name.c_str(),csql.c_str(),where_expr.c_str(),group_expr.c_str(),order_fld.c_str());
///< 生成分页查询SQL语句
string sql = pdbor->GetDBExt()->PageQuery(tsql,cond->begin_pos_,cond->page_size_);
AUTO_QUERY_RECORDSET(CRecordset,prs,pdbor);
///< 执行查询
prs = pdbor->Query(adCmdText,sql.c_str());
///< 查询结果输出到对象
CRecordsetBindObject<CGoodsSale> binder;
binder.BindRecordset(prs);
binder.BindField(NEW_FIELD_BIND(CGoodsSale,ORM_FIELD_TYPE_STRING,0,barcode_,0));
binder.BindField(NEW_FIELD_BIND(CGoodsSale,ORM_FIELD_TYPE_STRING,0,goods_name_,1));
while(!prs->IsEof()) {
CGoodsSale *item = binder.ToObject();
v.push_back(item);
prs->Move();
}
return 0;
}
2.资源
- CPageCond在common\base_type2.h文件中定义
- CPagizeHelper对应的定义文件和实现文件为common目录下的PagizeHelper.h/PagizeHelper.cpp.
3.定义
- 协议参数
///< 请求消息参数名
#define PAGIZE_FLAG "#PAGIZE.FLAG" ///< 是否需要分页
#define PAGIZE_PAGE_NO "#PAGIZE.PAGE_NO" ///< 页号(从1开始)
#define PAGIZE_PAGE_SIZE "#PAGIZE.PAGE_SIZE" ///< 页大小
#define PAGIZE_COUNT_FLAG "#PAGIZE.COUNT_FLAG" ///< 是否返回总记录数,默认第1页自动返回记录总数
#define PAGIZE_PAGE_NO_DUP "#PAGIZE.PAGE_NO_DUP" ///< 是否在返回消息中包含页号
///< 返回消息参数名
#define PAGIZE_TOTAL "#PAGIZE.TOTAL" ///< 总记录数
这些参数的访问只通过CPagizeHelper进行。
- CPageCond
///< 分页条件类
class CPageCond {
public:
bool page_flag_; ///< 是否分页
///< 分页查询条件项
unsigned long begin_pos_; ///< 起始位置
unsigned int page_size_; ///< 每页记录数,默认20条
unsigned int page_no_; ///< 页号(从1开始)
bool count_flag_; ///< 是否返回总记录数,默认:false
bool page_no_dup_; ///< 是否在返回消息中记录当前页号
unsigned long total_rec_num_; ///< 总记录数
CPageCond():page_flag_(true),begin_pos_(0),page_size_(20),count_flag_(false),total_rec_num_(0),page_no_(1),page_no_dup_(false) {
}
};
- CPagizeHelper
///< 分页处理帮助类
class CPagizeHelper {
public:
string dbc_name_; ///< 操作的数据库连接名
public:
///< 从请求中获取分页条件信息
static void GetPageCond(CMsg *req,CPageCond *cond);
///< 把分页条件置入请求消息
static void PutPageCond(CMsg *req,CPageCond *cond);
///< 设置返回消息的分页结果信息(统计类)
static void PutPageResult(CMsg *out,CPageCond *cond);
static void GetPageResult(CMsg *out,CPageCond *cond);
///< 获取分页查询记录总数()
///< @param sql: 查询总数的SQL语句
///< @return 0:没有数据 1:有数据 -1:错误
int GetCount(const char *sql,CPageCond *cond);
///< 执行一个只返回一条记录的查询,把列值放入_variant_t数组
///< @return 0:成功 -1:失败
int QueryRecord(const char *sql,vector<_variant_t> &v);
};
4.说明
- 数据库扩展IDBExt接口中支持分页的方法有三种:PageResult,PageResult2,PageQuery.
PageQuery分页处理要求必须提供一个排序字段.
- 客户端使用CPagizeHelper:
static void PutPageCond(CMsg *req,CPageCond *cond); ///< 设置分页查询条件后,写入请求消息包
static void GetPageResult(CMsg *out,CPageCond *cond);
.请求时:
CMsg *req = new CMsg;
///< 设置消息内容
...
CPageCond cond;
cond.page_size_ = 50; ///< 每页50条记录
cond.page_no_ = 1;///< 查询第1页
PutPageCond(req,&cond);
Send(req);
.得到响应时,
CMsg *ans; ///< 返回的消息包
CPageCond cond;
GetPageResult(ans,&cond);
cond.total_rec_num_;///< 得到总记录数