数据存储引擎是本项目里比较有特色的模块。

特色一,使用接口来对应不同的数据库。数据库可以是Oracle、Sqlserver、MogoDB、甚至是XML文件。采用接口进行对应:

     public interface IWorkflowDB
     {
         List<Flow> GetFlows();
         bool SaveFlow(Flow flow);
         bool DeleteFlow(Guid flowId);

         FlowInstance GetFlowInstanceByInstanceId(Guid flowInstanceId);
         List<FlowInstance> GetFlowInstanceByFlowId(Guid flowId);
         bool SaveFlowInstance(FlowInstance flowInstance);
         List<FlowInstance> GetFlowInstancesListByUser(Person person = null);
         bool DeleteFlowInstanceByInstanceId(Guid flowInstanceId);

         bool SaveForm(Form form);
         bool DeleteForm(Guid formId);
         List<Form> GetFormList();

         bool AddStep(WorkflowStep workflowStep);
         bool DeleteStep(Guid stepId);
         List<WorkflowStep> GetStepList();

         bool AddBaseTable(WorkflowConstant.BaseTable baseTable, Dictionary<int, string> values);
         Dictionary<int, string> GetBaseTableData(WorkflowConstant.BaseTable baseTable);
         bool DeleteBaseTableValue(WorkflowConstant.BaseTable baseTable, int key);
     }

特色二,使用Oracle的SYS.XMLTYPE来存储数据,查询时使用辅助方法,或者XML查询表达式

这样系统里一共只用了四个表,包括一个临时表,每个表不超过三个字段。

WORKFLOW_SETTINGS表:(存储系统设置参数、流程等)

WORKFLOW_FORM表:(存储系统表单)

WORKFLOW_FLOW表:(存储流程实例)

还有一个temp表,一行一列,字段为CLOB类型。

XMLType里面存储的是什么呢?不错,正是各个类的实例,序列化后的字符:

实际存储的方式:

保存时:类的实例-->XML序列化-->直接用Oracle的XMLtype存储;

读取时:读出数据-->反序列化-->类的实例直接可用。

这样就能方便的解决实体模型或领域模型与数据库存储之间“阻抗不匹配的”的问题。而且XMLType可以被SQLServer等主流数据库支持,所以迁移到其他数据库也很方便;如果你要使用常规的建表规则进行存储,只要实现IWorkflowDB接口即可。

序列化反序列化的方法,使用了扩展方法,可以放在项目里任何一个静态类里:

         public static string ToSerializableXML<T>(this T t)
         {
             XmlSerializer mySerializer = new XmlSerializer(typeof (T));
             StringWriter sw = new StringWriter();
             mySerializer.Serialize(sw, t);
             return sw.ToString();
         }

         public static T ToEntity<T>(this string xmlString)
         {
             var xs = new XmlSerializer(typeof (T));
             var srReader = new StringReader(xmlString);
             var steplist = (T) xs.Deserialize(srReader);
             return steplist;
         }

注意:有些类不能被序列化,比如Dictionary<TKey,TValue>,需要自己写可序列化的类。

好啦,接下来是实现IWorkflowDB接口的OracleWorkFlowDBUtility类,以存储工作流表单为例:

存储:

         public bool SaveForm(Form form)
         {
             var formContent = form.FormContent;
             var formId = form.FormId;
             form.FormContent = string.Empty;

             var sql = string.Empty;

             DbHelperOra.ExecuteSql("truncate table WORKFLOW_TEMP");
             var para = new OracleParameter("formInfo", OracleType.Clob);
             para.Value = form.ToSerializableXML();
             DbHelperOra.ExecuteSql("insert into WORKFLOW_TEMP(content) values (:formInfo)", para);

             var paras = new[]
             {
                 new OracleParameter("formId", formId.ToString()),
                 new OracleParameter("formContent", formContent)
             };
             if (DbHelperOra.GetSingle("select count(*) from WORKFLOW_FORM where form_id = :formId",
                 ")
             {
                 sql =
                     "update WORKFLOW_FORM set FORM_INFO = (select sys.xmlType.createXML(WORKFLOW_TEMP.content) from WORKFLOW_TEMP), FORM_CONTENT = :formContent where FORM_ID = :formId";
             }
             else
             {
                 sql =
                     "insert into WORKFLOW_FORM(FORM_ID,FORM_INFO,FORM_CONTENT) values (:formId,(select sys.xmlType.createXML(WORKFLOW_TEMP.content) from WORKFLOW_TEMP),:formContent)";
             }

             ";
         }

读取:

         public List<Form> GetFormList()
         {
             var ds =
                 DbHelperOra.Query(
                     "select t.form_info.getclobval() form_info, form_content from WORKFLOW_FORM t");
             if (ds != null)
             {
                 ].Rows.Count);
                 ].Rows)
                 {
                     var str = dr["form_info"].ToString();
                     var form = str.ToEntity<Form>();
                     form.FormContent = dr["form_content"].ToString();
                     forms.Add(form);
                 }
                 return forms;
             }
             return null;
         }

删除:

         public bool DeleteForm(Guid formId)
         {
             try
             {
                 if(DbHelperOra.ExecuteSql("delete from WORKFLOW_FORM where form_id = :formid",
                     ")
                 return true;
                 return false;
             }
             catch (Exception ex)
             {
                 return false;
             }
         }

一切都很简单,没有恼人的一列列字段名,也不用ORM、代码生成器等,开发、维护效率大幅度提高。

数据访问类实例化在WorkflowService类里面

先定义私有变量:

private readonly IWorkflowDB _iWorkflowDb;

然后在类的构造函数里这么写:

        public WorkflowService(IWorkflowDB workflowDb, IWorkflowMethods workflowMethods)
         {
             _iWorkflowDb = workflowDb;
             _iWorkflowMethods = workflowMethods;

         }

使用简单工厂返回类的实例:

         /// <summary>
         /// 程序主调用方法
         /// </summary>
         /// <returns></returns>
         public static WorkflowService GetWorkflowService()
         {
             IWorkflowDB iWorkflowDb;
             try
             {
             string dbSavingProvider = WorkFlowUtility.GetConfiguration("DataBaseProvider").ToLower();
                 switch (dbSavingProvider)
                 {
                     case "oracle":
                         iWorkflowDb = new OracleWorkFlowDBUtility();
                         break;
                     case "sqlserver":
                         //iWorkflowDb = new SqlServerWorkFlowDBUtility();
                         //break;
                     default:
                         iWorkflowDb = (IWorkflowDB) Assembly.Load(dbSavingProvider).CreateInstance(dbSavingProvider);
                         break;
                 }

             }
             catch (Exception)
             {
                 throw new WorkFlowConfigurationNotImplementException("数据库配置失败!");
             }

这样能在不同的项目中自由配置数据存储方式了。

如果要提高查询效率,比如报表,就可以这么写查询:

 select rownum "序号", t.dw "单位",vt.groupname || vs.groupname "团支部",t.xh "学号",t.xm "姓名",t.xb "性别",t.csrq "出生年月", t.zzmm "政治面貌", t.zc "职称", t.gzsj "工作时间", t.lxdh "联系电话" from
 (select f.instance_id,
 f.instance_content.extract('//FlowInstance/Creator/@PersonId').getstringval() xh,
 max(decode(x.key,'c57e4eb1-834c-491f-a1b5-b8b67f1ed160',x.value,null)) dw,
 max(decode(x.key,'6008c07f-617b-4607-8fe2-6a384c75ea8a',x.value,null)) xm,
 max(decode(x.key,'1153c641-7567-44ce-85c8-fcb0230d5cf7',x.value,null)) xb,
 max(decode(x.key,'76936043-17e0-40b7-9adc-22e88d461082',x.value,null)) csrq,
 max(decode(x.key,'22c6f1c5-d07b-45ba-9752-1118fdafee4c',x.value,null)) zzmm,
 max(decode(x.key,'47b32ce0-828e-4179-bf11-2ace0028fda5',x.value,null)) zc,
 max(decode(x.key,'a5cd9229-c8f9-4fb4-ba4f-e8157eeefa04',x.value,null)) gzsj,
 max(decode(x.key,'9d2984f9-a5c5-474d-807a-cd756b961615',x.value,null)) lxdh
 from WORKFLOW_FLOW f,
 XMLTable( '/FlowInstance/FlowStepInstances/FlowInstanceStep/WriteValues/SerializableDictionary'
 passing f.instance_content
 COLUMNS ) PATH 'key',
 value ) PATH 'value') x
 where f.instance_content.extract('//FlowInstance/Flow/@FlowId').getstringval() = 'e2f35ac0-d5aa-4413-af54-2cf4fe3759ef'
 , ), 'YYYY-MM-DD')
 between  to_date('2015-01-01','yyyy-mm-dd') and to_date('2015-06-01','yyyy-mm-dd')
 group by f.instance_id, f.instance_content.extract('//FlowInstance/Creator/@PersonId').getstringval()) t
 left outer join vm_tuanwei_teachergr vt on t.xh = vt.gh
 left outer join vm_tuanwei_studentgr vs on t.xh = vs.xh

查出来的结果如下图:

好啦,大家对我数据存储方式有什么意见,可以就此进行讨论。

本系列导航:

  1. .net之工作流工程展示及代码分享(预告)
  2. .net之工作流工程展示及代码分享(一)工作流表单
  3. .net之工作流工程展示及代码分享(二)工作流引擎
  4. .net之工作流工程展示及代码分享(三)数据存储引擎
  5. .net之工作流工程展示及代码分享(四)主控制类
  6. .net之工作流工程展示及代码分享(五)前端交互

.net之工作流工程展示及代码分享(三)数据存储引擎的更多相关文章

  1. .net之工作流工程展示及代码分享(四)主控制类

    现在应该讲主控制类了,为了不把系统弄得太复杂,所以就用一个类作为主要控制类(服务类),作为前端.后端.业务逻辑的控制类. WorkflowService类的类图如下: 该类的构造函数: public ...

  2. .net之工作流工程展示及代码分享(二)工作流引擎

    在介绍完表单类的时候,接下来介绍工作流引擎,主要由四个类组成,分别是流程.流程步骤.流程实例.流程步骤实例类. 流程类: [Serializable] public class Flow { [Xml ...

  3. .net之工作流工程展示及代码分享(一)工作流表单

    Workflow表单的作用是能够在客户端进行表单设计,然后在流程中动态开放哪些输入框可以供用户填写. 在这里我扩展了一个常用的WebEditor工具——KindEditor,能够插入自定义的html符 ...

  4. .net之工作流工程展示及代码分享(预告)

    最近在帮公司做一个工作流程序模块,要求是可以嵌入到各种现有的程序中去.我想把自己制作的思路和过程同大家分享. 先上一张结构图: 由于该项目我一个人做,所以系统结构不能太复杂. 用到的技术主要有:DDD ...

  5. net之工作流工程展示及代码分享(记录)

    http://www.cnblogs.com/thanks/p/4183235.html

  6. JAVA基础代码分享--DVD管理

    问题描述 为某音像店开发一个迷你DVD管理器,最多可存6张DVD,实现碟片的管理. 管理器具备的功能主要有: 1.查看DVD信息. 菜单选择查看功能,展示DVD的信息. 2.新增DVD信息 选择新增功 ...

  7. 一款WP小游戏代码分享

    首先声明游戏是H5的代码,当然游戏部分不是我写的,感谢@LeZhi的分享,关于H5我还在学习,这里只是简单介绍一下如何把一款现成的H5游戏封装成一款WP游戏(当然也可以做成Windows游戏). 大家 ...

  8. JAVA基础代码分享--求圆面积

    问题描述 用户输入圆的半径,计算并显示圆的面积 代码分享 /** * @author hpu-gs * 2015/11/25 */ public class Circle { public stati ...

  9. JAVA基础代码分享--学生成绩管理

    问题描述: 从键盘读入学生成绩,找出最高分,并输出学生成绩等级. 成绩>=最高分-10  等级为’A’   成绩>=最高分-20  等级为’B’ 成绩>=最高分-30  等级为’C’ ...

随机推荐

  1. PHP生成验证码及单实例应用

    /* note: * this 指向当前对象本身 * self 指向当前类 * parent 指向父类 */ /* 验证码工具类 * @author pandancode * @date 20150- ...

  2. IO-02. 整数四则运算(10)

    本题要求编写程序,计算2个正整数的和.差.积.商并输出.题目保证输入和输出全部在整型范围内. 输入格式: 输入在一行中给出2个正整数A和B. 输出格式: 在4行中按照格式“A 运算符 B = 结果”顺 ...

  3. Python积木之with

    简而言之,with 语句是典型的程序块 “try catch finally”的一种模式抽取.python的作者在PEP343中写道 “ This PEP adds a new statement & ...

  4. 环信ipv6适配

    环信2.2.5及之后版本才适配了ipv6.可以自己搭配个ipv6环境,在ipv6环境下2.2.5以下版本无法登录.把整个sdk换成2.2.5版本项目需要改动的地方实在太多. 那么就部分换一下,适配ip ...

  5. [cc150] 括号问题

    Implement an algorithm to print all valid ( properly opened and closed) combinations of n-pairs of p ...

  6. Shell学习笔记 ——第二天

    1.显示日期 date  |   cal   cal 2010  cal 2 2010 2.改变文件拥有者 chown 3.改变文件权限 chmod 4.显示当前目录 pwd 5.查看文件尾部内容,并 ...

  7. VS生成时复制文件到指定目录

    1.右键项目属性,选择生成事件,再点击"编辑后生成事件",可以直接在编辑框内填写命令行,如图: 2.也可以在弹出的编辑框内,写命令,$(ProjectDir)这种是系统的宏路径,具 ...

  8. 在centos7上编译安装nginx

    题前,先放一个有图有真相的博客链接:https://www.cnblogs.com/zhang-shijie/p/5294162.html 虽然别人说的很详细,但还是记录一下 1.VMWare Wor ...

  9. 关于Numba开源库(Python语法代码加速处理,看过一个例子,速度可提高6倍)

    关于Numba你可能不了解的七个方面 https://yq.aliyun.com/articles/222523 Python GPU加速 (很详细,有代码练习)https://blog.csdn.n ...

  10. 剑指Offer 11. 二进制中1的个数 (其他)

    题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 题目地址 https://www.nowcoder.com/practice/8ee967e43c2c4ec193b040e ...