NaviPlat框架技术白皮书.场景解决方案

      不同的场景,我们有很多解决方案,以下的解决方案是本人在日常开发时积累下来的,希望对大家有所帮助.

场景1:取Db数据

这里有很多种方式,比如通过sql语句,sql语句又包含是否使用{0}格式化sql语句,是否使用参数化sql语句,也有可能直接拼接;还可以使用存储过程,返回值是datatable对象也可以.

本类库中有枚举类型WhereStyle,表示Sql语句中Where条件的拼接方式,目前支持3种方式,如图-19所示

clip_image001

图-19

调用方式如图-20所示

clip_image003

图-20

说明

1. 传入参数是Dictionary泛型对象,并不是SqlParameter类型或{0}样式,原因是调用的地方并不需要引用SqlParameter类型数据,层与层之前的传递只使用DataSet,DataTable或Dictionary泛型对象,这样层与层之间保持了松耦合

2. 使用参数化时,@是针对SqlServer的,:是针对Oracle.后台是Oracle的时候,也可以使用@关键字.因为某些人的习惯使用SqlServer或Oracle.在后台会做统一替换处理

场景2:操作其他Db数据

我们在开发Db管理软件时,在保持连接一个固定Db的时候,难免要连接其他Db同时操作两个数据库.比如:两个产品间数据同步.这里有两种情况,第一种情况是对方有WebService接口直接调用即可;另一种情况就是啥都没有,只提供Db连接串,还不确定是何种Db,可能是Oracle,可能是SqlServer.所以,要支持同时获取其他Db的情况.调用和实现方式如图-21和图-22所示

clip_image004

图-21

clip_image006

图-22

说明

1. 继承自接口

2. DataBaseType是个枚举类型,表示Db类型.目前支持SqlServer,Oracle和OleDb

场景3:取外部文件数据

在开发Db类型软件时,还需要与外部文件非Db数据交互,比如Excel或Doc等.我们同样需要提供一系列的方法支持此种操作.以Excel文件为例,一个xls文件,可能包含多个Sheet页,此类库支持同时获取一个文件多个Sheet页数据.实现方式如图-23所示

clip_image007

图-23

说明

1. 只需声明ParmXlsParm对象即可,定义好Xls文件名称和Sheet名称,parm_xls.SheetName是个IList<string>泛型对象,可以传入多个SheetName

2. 在整个类库中,涉及到读取Excel文件的方法,我们只需这样调用即可,这样就保证的方法功能的唯一性;

场景4:执行Sql语句

执行Sql语句,就是UI层操作完成的数据,需要保存至Db中,Sql语句可能是字符串,也可能是参数化;可能是一条,也可能是多条,多条的话就要使用事务,数据提交失败后,错误需要记录下来.类库中提供如何几种方法,如图-24所示

clip_image009

图-24

说明

1. 我们在执行Sql语句时,参数也同样是Dictionary泛型对象,这样与前面获取Db数据时一致.

2. 使用DbSqlStringAndParameter对象,同时支持OracleParameter和SqlParameter参数,定义和赋值如图-25和图-26所示

clip_image010

图-25

clip_image011

图-26

说明

1. DbParameter[]对象可以存储SqlParameter[]或OracleParameter[]对象

场景5:UI控件赋值和赋值

我们从Db中取出数据以后,需要展示在UI控件上,以便用户操作.比较常见的方式就是this.txt_textbox.text = XXX.如果控件不多的时候,这样处理是可以接爱的,若有几十个,可能就有些繁琐了.此类库中的处理方法如图-27和图-28所示

clip_image013

图-27

clip_image015

图-28

说明

1. 控件赋值的语句是this.SetControlValueByDataRow方法,这个方法有3个参数,定义如下

参数1:Dictionary<string,string> adic_controlname,

参数2:Dictionary<string,string> adic_controltype

参数3:DataRow arow_data

前两个参数是实体类构造函数中定义的ControlName和ControlType属性

2. 控件取值的语句是this.GetDbColumnValueByControlToDictionary方法,这个方法有2个参数,定义如下

参数1:Dictionary<string,string> adic_controlname

参数2:Dictionary<string,string> adic_controltype

场景6:UI控件值清空

数据保存完毕之后,需要将控件值初始,这里的初始有两种意思,第1种是清空,即赋值空;第2种情况是恢复操作前的控件值,比如之前有初始值A,操作完成后也要恢复成A.类库中提供了4种方法完成此项操作,如图

clip_image016

图-29

场景7:执行存储过程

在执行Sql语句的同时,我们还需要执行Db中的存储过程.而且,存储过程的返回值或参数有也所不同,这里基本包含了所有的情况.如图-30所示

clip_image018

图-30

这里说明一下每组的最后一个方法参数

String as_procedure //存储过程名称

Dictionary<string,object> adic_parmname //存储过程参数列表

Dictionary<string,string>adic_parmdirection //存储过程参数方向,分out和in等

Ref Dictionary<string,object>adic_parmvalue //存储过程参数返回值

场景8:多页面中控件加载同一表数据

在设计很多页面时,有些基础数据是非常被常用到的.例:科室,检验项目等.这就是说,我们在加载不同页面的下拉菜单时,他们的数据源是一致的,如果每个页面sql获取一下,显然是不方便的.此类库的解决方案如图-31所示

clip_image020

图-31

说明:

1. 把真正的SQL语句放在配置文件中,通过标识符调用.这样SQL语句变动时,只需修改一处即可

场景9:不同客户针对同一表,字段要求不同

这个业务场景的意思是说,某张业务表A,10个客户都共用其中的15个字段,但每个客户又有他自己的个性化字段,比如客户1需要Column1,客户2需要Column2.这样,我们前后台交互数据的时候,非常麻烦.因为我们要根据不同的客户来加载不同的SQL语句.配置文件如图-311所示

clip_image022

图-311

此类库的处理方法是

1. 针对表A预留20个字符串字段,备用.在创建实体类的时候,全部创建.

2. 每个客户所用到的字段可以配置,配置的同时,标注每个字段的真正含义.这样我们在用实体类操作数据的时候,只需操作客户所涉及到的字段即可.

3. 此方法存在缺点,是用有限的方案解决无限的需求,并不是动态的去解决.弥补的方法是若备用的20个字段不够用,再额外创建.单独建表保存数据.

场景10:UI页面加载菜单栏,工具栏等

UI页面需要操作数据,我们可能会通过增加菜单栏,工具栏,控件右键菜单或按钮来增加操作的功能点,但是,客户的功能点可能会随时变化,或者功能点的名称也会经常修改.如果每次修改代码进行处理的话,显示不是好方法.此类库解决方案如图-32所示

clip_image023

图-32

clip_image025

图-33

clip_image026

图-34

说明

1. 把菜单项,工具栏配置至Db表或XML文件,如图-33所示.这里配置它们的名称和标题.

2. 至关重要的控件单击事件绑定已经在底层类库中处理,我们编写事件代码时只需override即可.如图-34所示.这样处理的好处是事件名称规范,有问题可以快速定位

场景11:业务层调用

这个其实并不算是场景,说是解决方案更为贴切.是这个意思,我们开发产品的时候,会把产品人为的划分为若干模块,如ERP中的进销存,那么进销存的模块中,又区分通用部分和非通用部分,非通用部分就是我们常说的业务层,依据不同客户定制开发.

这里要先说下业务层颗粒度的问题,每个模块会划分为若干子模块,业务层的类创建,是依据每个子模块创建一个与之对应的业务类,还是为这个模块创建一个大的业务类,然后在这个业务类中再逐步拆分.此类库的解决方案是后者,如图-35所示

clip_image027

图-35

场景12:编写SQL语句

我们在开必Db类软件时,肯定会与Db打交道,编写SQL语句是必修课.如何更好的编写SQL语句,也是需要讨论的一个话题.我见过的公司里,有的在UI层直接编写,有时还通过多表关联,其复杂程度使得新上手的开发员很难继续,个人认为这并不是好的开发方式,因为它把容易变化的东西暴露给了开发员.如果我们需要增加或修改一个字段,无疑要修改页面,编译,发DLL文件给客户,从而增加了开发时间.

此类库的解决方案是将SQL语句统一放至配置文件(Db或XML均可),通过标记符调用,如图-36所示

clip_image029

图-36

调用时,只需如图-37所示

clip_image031

图-37

在UI层拼接Where条件(Dictionary类型),直接调用GetTableDataAreaByName方法即可

说明

1. 比较复杂的SQL语句,如多表等,可以制作成视图,总之,尽量减少SQL语句的复杂度.

2. 若是多条件,可以采用{0},{1}格式化方式,UI层只需传入替换参数即可.

3. 调用的数据支持存放在多处,比如一部分存放在Db,一部分存放在Xml均可.只需设置datalocation属性为DbAndXml即可

场景13:日志管理

日志,是管理类软件的必备模块之一,尤其对于开发员更为重要.良好的日志可以帮助开发员快速的找到问题所在.

此类库中日志的解决方案是将将日志进行分类,逐个类型分别处理.日志类型包括

l Db日志

l 用户登录日志

l 用户事件日志

l 用户操作日志

l 异常信息

如图-38所示,是日志管理模块中的登录日志管理

clip_image033

图-38

场景14:网格控件栏目设置

这个场景其实非常小,放在此处做为场景讲,有些没有必要.主要技术点在加载网格控件栏目上,对于展示在UI页面上的东西,客户有时头脑一热,就会增加或减少个字段,字段标题也有可能要换下,这都是很有可能.我曾经专门处理过一个需求,就是专门修改某个页面中网格控件的需求.现在想想,确实没有必要.如果这些东东可以通过配置文件处理,实施员就可以解决.该需求在此类库的解决方案如图-39所示

clip_image035

图-39

说明

1. 我们将某个网格控件的栏目信息配置起来,包括栏目名称,标题,长度,是否复选框,下拉菜单等.

2. 修改时,只需修改配置文件即可.

3. 加载方式如图-40所示

clip_image037

图-40

场景15:公用基础编码

我们在开发一个产品时,难免会用到很到数据,这就要建立很多表.但有些表,功能相似,数据量也不大,而且非常常用.可以将这些数据统一建立一张表中存放,维护时,只需维护一个地方即可.

相信这个方法是大多数人的通用方法,现在说下此类库里的解决方案.除去上述建表之外,还通过XML文件的存储形式,同样保存了公用基础编码.如图-41所示

clip_image039

图-41

这样我们在加载基础编码的时候,就需要加载两部分.一部分是Db,另一部分是XML.之所以这样设计,是因为我们可能需要临时为客户加某些公用基础编码,但对其他客户又没有什么用处.就可以临时存放在此.这也是处理客户个性化的方法之一

我们在系统加载数据时,调用方法请参照场景12的情况即可.

场景16:多级分层代码布局

不知道大家我们在编写代码过程中,有没有考虑过一行代码写到什么位置最优呢?其实代码也是分级别和层次的,通俗地说,我们都知道导出的代码要写得比较底层,因为这个功能非常基础和通用,写到底层比较方便.

同样的道理,我们在编写常规业务模块代码时,也是这样的,比如这串代码只是这个模块调用,那串代码被同一系统内几个模块调用,或者代码可能被几个模块同时调用,我们有没想过如何处理呢?

本类库的解决方案如图-42所示

clip_image040

图-42

说明

1. 后缀Model在UI层与Db层之间,用于两层之间的交互

2. AssiCodeModel和ToolBarModel是Author系统功能模块内某个功能模块的Model类

3. ModuAuthorModel是Author系统功能模块内公用的Model类,可被每个子模块调用

4. ModuAuthorFacade属于外观层,是Author系统功能模块对外的接口

5. ModuAuthorBusiness类相当于业务层,其实它应该在另外项目中(由于Author功能模块是必备模块,因此放在此处!)

由此得出,不同的代码有它不同的位置来存放,我们要预留出这样的接口,才能方便以后的扩展.即使移植也是比较简单的!

 

      以上部分介绍的是本框架能够解决的常用业务场景,希望大家提出更多的业务场景,丰富这个框架,谢谢!

  下一篇将介绍本框架的类库布局

你可能感兴趣的:(解决方案)