插件开发技术说明(15)---单据处理编程模式
2015-09-24 01:52
489 查看
以CSale为例说明.
.增加BIND_DECLARE(CSale),宏BIND_DECLARE定义与绑定有关的静态成员和方法.
.单据类实现文件中声明变量,字段绑定信息初始化.
CSale::Init()在插件的Initialize函数中调用.
如果需要,重载基类的函数:
如校验单据数据有效性.对明细进行合计.
实现:
这样定义后,就具有了许多常用的功能.无需增加其它代码.
EVENT_NEW_PURCHASE在slic_event.h中定义.
sale.Insert调用的是CSheet的方法,不需要再对CSale编写代码.
以下代码中的sale.Load加载整张单据,而用sale.Select则可以读所需的字段,减少开销.
下列代码是iep_b插件处理销售单状态改变的代码
(1)统一字段映射:
此前CRecordsetBindObject和ITableHandler分别执行绑定,分别对应查询和插入/修改/更新操作.
查询时,
插入/修改/更新时:
。支持一主多从表:更复杂的结构以后扩展支持
。扩展单据基类CSheet,大幅降低单据业务处理的编程量,提高开发效率.
***已有的业务单据类实现若直接应用,可删除大量的代码.
。此模式可进一步延伸到非单据类,初步思路:
orm_helper.h中定义CORM类,承接CSheet中的若干功能.非单据类从CORM派生。
其中,Save是兼容性保留,待废弃.
int Update(const char *fld,...)暂未实现.
1.定义单据类
包括主表类和明细类.#include "RecordsetBinder.h" ///< BIND_DECLARE,... class CSale:public CSheet{ public: CSale():CSheet(2050) { } CSale(SLIC_SHEETID sheet_id):CSheet(2050,sheet_id) { } public: static int Init(); BIND_DECLARE(CSale) };.单据类实现2个构造函数.***注意要初始化单据类成员变量.上述代码略.
.增加BIND_DECLARE(CSale),宏BIND_DECLARE定义与绑定有关的静态成员和方法.
.单据类实现文件中声明变量,字段绑定信息初始化.
CRecordsetBindObject<CSale> CSale::binder_; CRecordsetBindObject<CSale::CSaleDetail> CSale::CSaleDetail::binder_; ///////////////////////////////////////////////////////////////////////////// CFieldBind CSale::fld_bind_[] = { FIELD_BIND3(CSale,sheet_id_,"SheetID",true), FIELD_BIND1(CSale,eid_,"EId"), FIELD_BIND1(CSale,co_eid_,"CoEId"), FIELD_BIND1(CSale,ref_sheet_id_,"RefSheetId"), FIELD_BIND1(CSale,user_id_,"UserId"), FIELD_BIND1(CSale,stock_id_,"StockId"), FIELD_BIND1(CSale,group_id_,"GroupId"), FIELD_BIND1(CSale,dept_id_,"DeptId"), FIELD_BIND1(CSale,send_type_,"SendType"), FIELD_BIND1(CSale,disc_value_,"DiscValue"), FIELD_BIND1(CSale,crm_value_,"CrmValue"), FIELD_BIND1(CSale,pay_type_,"PayType"), FIELD_BIND1(CSale,pur_flag_,"PurFlag"), FIELD_BIND1(CSale,pur_value_,"PurValue"), FIELD_BIND1(CSale,delivery_date_,"DeliveryDate"), FIELD_BIND1(CSale,delivery_address_,"DeliveryAddress"), FIELD_BIND1(CSale,contact_,"Contact"), FIELD_BIND1(CSale,contact_mobile_,"ContactMobile"), FIELD_BIND1(CSale,notes_,"Notes"), FIELD_BIND1(CSale,status_,"Status"), FIELD_BIND1(CSale,del_flag_,"DelFlag"), FIELD_BIND1(CSale,operator_,"Operator"), FIELD_BIND1(CSale,creator_,"EditOr"), FIELD_BIND1(CSale,create_time_,"EditDate"), FIELD_BIND1(CSale,from_id_,"FromId"), }; CFieldBind CSale::CSaleDetail::fld_bind_[] = { FIELD_BIND1(CSale::CSaleDetail,eid_,"EId"), FIELD_BIND1(CSale::CSaleDetail,sheet_id_,"SheetID"), FIELD_BIND1(CSale::CSaleDetail,line_num_,"LineNum"), FIELD_BIND1(CSale::CSaleDetail,goods_id_,"GoodsId"), FIELD_BIND1(CSale::CSaleDetail,barcode_,"Barcode"), FIELD_BIND1(CSale::CSaleDetail,stype_,"SType"), FIELD_BIND1(CSale::CSaleDetail,icolor_,"IColor"), FIELD_BIND1(CSale::CSaleDetail,isize_,"ISize"), FIELD_BIND1(CSale::CSaleDetail,wp_rate_,"WPRate"), FIELD_BIND1(CSale::CSaleDetail,cost_,"Cost"), FIELD_BIND1(CSale::CSaleDetail,tax_rate_,"TaxRate"), FIELD_BIND1(CSale::CSaleDetail,bulk_price_,"BulkPrice"), FIELD_BIND1(CSale::CSaleDetail,pack_price_,"PackPrice"), FIELD_BIND1(CSale::CSaleDetail,old_bulk_price_,"OldBulkPrice"), FIELD_BIND1(CSale::CSaleDetail,old_bulk_price_,"OldBulkPrice"), FIELD_BIND1(CSale::CSaleDetail,bulk_qty_,"BulkQty"), FIELD_BIND1(CSale::CSaleDetail,pack_qty_,"PackQty"), FIELD_BIND1(CSale::CSaleDetail,pack_unit_qty_,"PackUnitQty"), FIELD_BIND1(CSale::CSaleDetail,promotion_sheetid_,"PromotionSheetID"), FIELD_BIND1(CSale::CSaleDetail,prefer_notes_,"PreferNotes"), FIELD_BIND1(CSale::CSaleDetail,disc_value_,"DiscValue"), FIELD_BIND1(CSale::CSaleDetail,gift_qty_,"GiftQty"), FIELD_BIND1(CSale::CSaleDetail,gift_flag_,"GiftFlag"), FIELD_BIND1(CSale::CSaleDetail,stk_qty_,"StkQty"), FIELD_BIND1(CSale::CSaleDetail,notes_,"Notes"), }; ///////////////////////////////////////////////////////////////////////////// int CSale::Init() { ISheetTypeInfo *sti = CDataEnv::env_->sheet_type_mgr_->Add(2050,"t_ven_sale","t_ven_saleitem",0); binder_.SetFieldBindInfo(&fld_bind_[0],sizeof(fld_bind_)/sizeof(fld_bind_[0]),false); CSale::CSaleDetail::binder_.SetFieldBindInfo(&CSale::CSaleDetail::fld_bind_[0],sizeof(CSale::CSaleDetail::fld_bind_)/sizeof(CSale::CSaleDetail::fld_bind_[0]),false); sti->SetBinder(&binder_,&CSale::CSaleDetail::binder_,0); return 0; }
CSale::Init()在插件的Initialize函数中调用.
int CSd::Initialize() { parent::Initialize(); CSale::Init(); return 0; }
如果需要,重载基类的函数:
如校验单据数据有效性.对明细进行合计.
public: void AddDetail(CSheetDetail *pDetail,short index=0); int Check();
实现:
///////////////////////////////////////////////////////////////////////////// int CSale::Check() { return this->pur_value_ >= this->disc_value_; } ///////////////////////////////////////////////////////////////////////// void CSale::AddDetail(CSheetDetail *pDetail,short index) { CSale::CSaleDetail *detail = (CSale::CSaleDetail*)pDetail; detail->sale_ = this; detail->line_num_ = details_.size()+1; this->pur_value_ += detail->bulk_qty_*detail->bulk_price_; this->pur_value_ += detail->pack_qty_*detail->pack_price_; this->pack_qty_ += detail->pack_qty_; details_[index]->push_back(detail); }
这样定义后,就具有了许多常用的功能.无需增加其它代码.
2.使用示例
2.1插入新单据
以下是iep_b处理EVENT_NEW_PURCHASE事件的代码.EVENT_NEW_PURCHASE在slic_event.h中定义.
#define EVENT_NEW_PURCHASE 7800 /// 采购订单代码:
//////////////////////////////////////////////////////////////////////////////// int CIEPB::OnNewPurchase(CEvent *e) { vector<string> vs; CHECK_EVENT_REFER(e,vs,2,-1); ///< 事件主体 unsigned int eid = atol(vs[0].c_str()); unsigned __int64 sheet_id = _atoi64(vs[1].c_str()); vector<string> vs2; CHECK_EVENT_PARA(e,vs2,1,-1); ///< 事件参数 unsigned int co_eid = atol(vs2[0].c_str()); mpm_ns::CPurchase purchase; int ret = purchase.Load(sheet_id); ///< 读入采购订单信息 if (ret!=1) return ret; sd_ns::CSale sale; Purchase2Sale(purchase,sale); ///< 采购订单转销售单 if (sale.ApplyID()) return -1; if (sale.Insert()) ///< 插入订单 return -1; return 0; }
sale.Insert调用的是CSheet的方法,不需要再对CSale编写代码.
2.2读入单据
读入指定的单据.以下代码中的sale.Load加载整张单据,而用sale.Select则可以读所需的字段,减少开销.
下列代码是iep_b插件处理销售单状态改变的代码
//////////////////////////////////////////////////////////////////////////////// int CIEPB::OnSaleStatusChanged(unsigned __int64 sheet_id,int status) { sd_ns::CSale sale; sale.sheet_id_ = sheet_id; int ret = sale.Select("purflag","refsheetid","fromid",0); ///< 仅读取所需要的字段 // int ret = sale.Load(sheet_id); ///< 加载整张单据 if (ret==-1) return -1; if (ret==0) {/// ==0无此单据 return 0; } if (sale.ref_sheet_id_==0) ///< return 0; if (sale.pur_flag_==0) { COrder order; order.sheet_id_ = sale.ref_sheet_id_; if (order.UpdateStatus(status)) return -1; } else if (sale.pur_flag_==1) { CPurchase purchase; purchase.sheet_id_ = sale.ref_sheet_id_; if (purchase.UpdateStatus(status)) return -1; } return 1; }
3.优化内容
。对象与字段绑定:可大幅降低代码量,并降低开销,提高处理性能(1)统一字段映射:
此前CRecordsetBindObject和ITableHandler分别执行绑定,分别对应查询和插入/修改/更新操作.
查询时,
CRecordsetBindObject<CSale> binder; binder.BindRecordset(prs); binder.BindField(NEW_FIELD_BIND(CSale,ORM_FIELD_TYPE_ULONG,0,eid_,"EId"));
插入/修改/更新时:
ITableHandler *th = CDataEnv::env_->db_helper_->NewTableHandler(pdbor,"t_Ven_SaleItem"); AUTO_POINTER_NODECLARE(ITableHandler,th); th->BindField("Eid",(char**)&this->eid_,sizeof(this->eid_));(2)预绑定:不需要再运行时每次进行绑定,减少cpu开销,提高处理速度
。支持一主多从表:更复杂的结构以后扩展支持
。扩展单据基类CSheet,大幅降低单据业务处理的编程量,提高开发效率.
***已有的业务单据类实现若直接应用,可删除大量的代码.
。此模式可进一步延伸到非单据类,初步思路:
orm_helper.h中定义CORM类,承接CSheet中的若干功能.非单据类从CORM派生。
3.附:相关实现代码
3.1CSheet虚函数
virtual CRecordsetBindObjectBase* GetBinder() { return 0; } virtual CRecordsetBindObjectBase* NewBinder(const char *fld,...) { return 0; } virtual CRecordsetBindObjectBase* NewBinder(const char *fld,va_list arg) { return 0; } ///< 检查对象数据是否有效 ///< @return -1:错误 0:无效 1:有效 virtual int Check() { return 1; } virtual int ApplyID(); ///< 生成单据编号 /// @return 0-成功 -1-失败 1-存在主键冲突 virtual int Insert(short on_dup_error=2); ///< on_dup_error 忽略-1,按错误处理-2,更新-3 virtual int Update(short inc_detail); ///< 修改单据 inc_detail:是否更新明细 virtual int Update(const char *fld,...); ///< 修改指定的单据字段 virtual int Select(const char *fld,...); ///< 查询指定的单据字段 virtual int Delete(); ///< 删除单据 virtual int DeleteDetail(); ///< 删除明细 virtual void ClearDetail(short index=0); virtual void ClearAllDetail(); virtual void AddDetail(CSheetDetail *pDetail,short index=0); virtual int Load(SLIC_SHEETID sheet_id,bool load_detail=true); ///< 加载单据信息 virtual int LoadDetail(); ///< 加载明细信息 virtual int Save(); ///< 保存单据 virtual int UpdateStatus(int nStatus);
其中,Save是兼容性保留,待废弃.
int Update(const char *fld,...)暂未实现.
3.2BIND_DECLARE宏
#define BIND_DECLARE(CLS) \ static CFieldBind fld_bind_[];\ static CRecordsetBindObject<CLS> binder_; \ CRecordsetBindObjectBase* GetBinder() { return &binder_; }\ CRecordsetBindObjectBase* NewBinder(const char *fld,va_list arg) { \ CRecordsetBindObject<CLS> *binder = new CRecordsetBindObject<CLS> ; \ const char *p = fld;\ while(p) { \ CFieldBind* f = binder_.GetField(p); \ binder->BindField(f); \ p = va_arg(arg,const char *); \ } \ return binder; \ }\ CRecordsetBindObjectBase* NewBinder(const char *fld,...) { \ va_list vl;\ va_start(vl,fld);\ CRecordsetBindObjectBase *binder = NewBinder(fld,vl);\ return binder;\ }\
相关文章推荐
- Java常见问题1
- [C++STL]stl源码剖析
- c++设计模式-----责任链模式
- java输入输出流(内容练习)
- leetcode: (260) Single Number III
- Yii2请求,报400错误
- 升级jdk8后系统报错解决:java.lang.RuntimeException: java.io.IOException: invalid constant type: 18
- PHP跨域Ajax解决方案
- [C++基础]在构造函数内部调用构造函数
- Python新浪微博爬虫程序
- java 数据库连接池配置问题
- 四 NoteList.java
- 初学Python-第五章练习题
- Java反射
- netbeans无法连接数据库
- eclipse中使用maven插件的时候,运行run as maven install的时候报错
- support v7中recycleView在Eclipse中的使用问题
- 《细说PHP》分页源代码
- x264测试代码
- 关于C++多种数据类型四则运算的精度问题