• 【自然框架】之表单控件(一)实体类(Class)VS 字典(Dictionary)


    用一个具体一点的例子来说一下,我实现单表的添加、修改的思路和方式,顺便和三层里的实体类的方式做一下对比。

    一、我的拆分思想之一

          简单的操作和复杂的操作分离开来,即简单的操作简单处理,复杂的操作其他方式处理。比如,单表的添加、修改操作,这个比较简单,没有什么复杂的业务逻辑,甚至可以说没有业务逻辑,那么这样的操作,我们就可以“提炼”出来单独处理,用一种简单的方法搞定。

    二、适用范围

          这个要说明白了,否则会比较麻烦:)

          1、 信息管理类项目,就是使用关系型数据库保存数据的项目。比如网站的后台管理、OA、CMS、CRM、企业定制开发等。
          2、 B/S方式。
          3、 单表的添加、修改。(其实主从表的也可以使用,只是复杂了一点点,所以第一步先说简单的。)

          您可能会说,这个适用范围是不是太小了,没有什么意思。把范围限定小一点,是想控制一下,范围弄大了,就不好讨论了。

          这个只是第一步。简单的操作简单处理吗。

    三、三层里面使用实体类来实现添加、修改数据的步骤。

          这里只说编码部分,不说调研、设计等部分。我们就以新闻信息为例,实现添加、修改新闻的功能。      

          1、 定义实体类。

    定义 class News

          2、 拖拽控件,绘制表单。
          3、 从控件里面取值,然后给实体类赋值。

    myNews.NewsTitle = txtTitle.Text;
    myNews.NewsContent 
    = txtContent.Text;
    myNews.AddedTime 
    = DateTime.Now;

          4、 处理SQL语句。

           这里有许多的实现方式,可以使用SQLHelp、微软的企业库、自己封装的类库、ORM、LinQ to SQL等,只是不管用什么方式,最终都是要得到一个SQL语句(包括参数化的SQL语句)。

     
          5、 提交给数据库。
          6、 如果是修改的话,还有一个从实体类里面取值,给控件赋值的步骤。

          主要步骤就是这些,当然还有一些数据验证、逻辑处理等。由于单表的添加、修改比较简单,基本上没有什么业务逻辑,所以这个就暂且不提。注意:并不是说不用处理了。

          问题:“冗余”代码过多。我们先看上面说的第三步,有一个字段就要写一行给实体类赋值的语句,如果一个项目有100个表,一个表里面有10个字段,那么就是1000个字段,至少1000行的语句,工作量不少嘛。而这些代码基本一致,除了控件名、类、属性不一样之外,都是一样的。这是必须要写,但是有没有什么“技术含量”的代码。当然了您可以使用代码生成器,可以找好几个人来分工。但是这只是治标不治本,并没有从根本上减少代码。

          那么如何从根本上减少代码呢?(可能您要问了,减少代码有什么好处呀?减少代码可以缩短时间,减少出错的机会,减少检查代码的工作量,减少修改代码的机会。)

    四、我的思路

          ORM的思路是把类和表一级的做对应,类的属性和字段一级的作对应,而我的想法是把表、字段“提升一个级别”,即让“字段”和“类”作对应,“表”和“集合”做对应。而集合我选择了字典(Dictionary)。

          我们先定义一个类ColumnsInfoBase ,这个类要对字段进行描述。 

    public class ColumnsInfoBase        
    {
            
    #region 字段的基本信息的描述
            
    /// <summary>
            
    /// 配置信息里面的字段的标识
            
    /// </summary>
            public int ColumnID = 0;

            
    /// <summary>
            
    /// 数据库里的字段名称
            
    /// </summary>
            public string ColSysName = "";

            
    /// <summary>
            
    /// 显示给客户看的名称
            
    /// </summary>
            public string ColName = "";

            
    /// <summary>
            
    /// 字段类型,int nvarchar 等
            
    /// </summary>
            public string ColType = "";

            
    /// <summary>
            
    /// 字段大小
            
    /// </summary>
            public Int32 ColSize = 0;

            
    /// <summary>
            
    /// 字段值
            
    /// </summary>
            public string ColValue;

            
    #endregion

        }

          然后定义一个字典, 

    Dictionary<int, ColumnsInfoBase> dic_BaseCols = new Dictionary<int, ColumnsInfoBase>();

          再然后,我们把的实例放到字典里面,这样我们的准备工作就做好了,下面看看如何实现从控件里面取值的操作。 

    Code

          有了字典就方便了,取值的时候我们来一个遍历就搞定了,

    ColumnsInfoBase bInfo;
    IControlMgr ControlValue 
    = null;   //取值的接口

    foreach (KeyValuePair<int, ColumnsInfoBase> info in dic_BaseCols)
    {
        bInfo 
    = (ColumnsInfoBase)info.Value;
                
        ControlValue 
    = (IControlMgr)this.FindControl("c_" + bInfo.ColSysName);
        bInfo.ColValue 
    = ControlValue.ControlValue;
    }

      

          您可能要问了:这个ControlValue是什么呀,你用的是什么控件呀?.net自带的控件里面确实没有这个属性,而且郁闷的是不同的控件,取值的属性名称还都不一样(我并不是说这么做不对)。不一样怎么在遍历里面取值呀?自带的没有,那我们就定义一个接口让他有不就行了吗?(听说3.5里面可以使用扩展属性的方式了) 

          我定义一个接口,然后继承.net自带的控件,在实现这个接口就可以了。您说,这多麻烦呀,又是继承又是接口的,这要弄出来多少个控件呀?对于B/S来说,文本框、列表框、下拉列表框、复选框、复选组、单选组等,常用的就是这几个,把不常用的都加起来也不超过15个。常用的几个我已经都做好(点击下载)了,总共的代码才几十行(实现接口的代码)。相比我上面说的1000行代码可是少多了。而且这些控件,不仅可以在一个项目里面使用,其他的项目里面也可以使用,这样算起来节省的代码就更多了。

          再看上面说的第四步,其他的方式是怎么实现的我也不太清楚,我就不多说了,就说我的方法。我的方法就是写一个函数来处理SQL语句,可以拼接成SQL语句,也可以拼接成参数化的SQL语句(顺便处理一下储存过程的参数),还可以调用储存过程来处理。就是说这一步也可以只用一个函数就搞定,封装成DLL文件之后,各个项目就可以直接使用了。这样代码行数和字段数量就没有什么关系,即字段的增减并不会影响代码的行数。

          最后再来看看定义的部分。
          您一定会说了,我的这个方法虽然在取值的时候用一个遍历就可以了,但是在定义的时候可是多写了好多行的代码呀?
    其实我只是定义了一个类(ColumnsInfoBase),而 Title (ColumnsInfoBase Title)只是一个实例。定义类我是没有找到偷懒的方法,但是得到实例却是可以偷懒的。ColumnsInfoBase的属性类型都是字符串或者数字的,那么这些属性值就可以放在“配置信息”里面来存放,我可以做一个文件,把一个表单需要的字段的信息都放在这个文件里面,然后在用的时候读取出来,再做一个遍历就OK了。当然这回是遍历读取出来的配置信息,而不是遍历字典。


          最后的最后,我们还是看看UI吧,第二步我说了,要拖拽文本框这样的控件,但是我们一定要手动拖拽吗?我们可以用代码生成器嘛,当然我还是不喜欢这种方式,原因就是我不知道一个字段到底对应什么控件,对控件要如何“描述”(比如文本框的宽度、最大字符数等)。这些用代码生成器如何来生成呢?23号活动的时候我问了一下,没什么办法,只能手动修改了。这就带来了一个很大的问题:手动修改了代码生成器生成的代码后,如果有变动(比如增加了几个字段)了怎么办?我就不能直接使用代码生成器生成的“新的代码”覆盖以前的代码了,因为我手动修改了。不知道您对这样的问题是如何解决的,您是不是有更好的办法呢?

          我的方法就是做一个表单控件,让这个控件自己new控件(比如文本框)出来,那么一个字段到底要new出来什么控件呢?加说明,就是给字段增加 在表单里面 表现成什么控件的说明(其实是一个标识)。至于表单控件如何绘制页面,下次再说。

    五、这种方法的优点:


          1、 增加字段、减少字段,可以不修改代码。增加字段就是往字典里面多加一个实例,减少一个字段就是少加一个实例,这样的话,还用修改代码吗?
          2、 字段名变化了也不用修改代码。
          3、 整理一下可以做成表单控件,这样就可以在多个项目里面通用了,节省更多的代码。试想,单表的添加、修改使用这样的表单控件来实现了,可以说不用写代码了,没有代码了还检查什么代码?修改什么代码?还怕代码风格不统一?(当然有一个前提,使用我的方法。我不是说一定要用,只是说我有这种方式。)
          4、 可以使用一个页面实现多个表的添加、修改。比如新闻的添加、修改使用页面,产品信息(简单的)也可以使用页面。其他的单表的添加、修改也可以使用这个页面,这样又省下了不少页面。


    六、缺点:
          1、 适用范围比较小。
          2、 如果想要找到一个字段,不是太直观。不适合业务逻辑复杂的情况。

    Ps:
          1、 ORM与UORM。
          ORM就是类和表的对应,它是完全不管UI的,这样做就很灵活,可是适应更多的情况。灵活度高了,工作量也就多了,我们还要去处理UI。
          而UORM就是把UI也划进来了。这样做灵活度降低、适用范围也小了,但是工作量却可以大大降低。
    我是一个小小的coder,工作量大就意味着要加班加班再加班,而且没有加班费。郁闷呀,所以我要给自己减负,从根本上降低工作量。

          2、 权限控制到字段。
          这要先向大家道歉了,本来想先写权限的,但是发现要想说好权限,还真不是一件容易的事情,要说明白我是如何“通用”的,就要先说依据的基础。恩,争取本周内结束。
          假设我们要把权限的粒度做细,细到控制表单里的每一个字段,那么对于这种方式来说就很容易了,控制字段就相当于控制字典里的一个实例,有权限则添加这个实力,没有权限则不添加这个实力。
    这是通用权限的一个基本思想,如果您没看懂也不要紧,过几天我会详细说明的。

    3、 关于代码生成器。
          其实代码生成器的原理和我的控件的原理是一样的,如果说代码生成器是事先编译的话,那么我的控件就是“运行时编译”。代码生成器要先生成代码,编译后才能使用。而我的表单控件呢,只要配置信息一遍,不用重新编译,立刻就能看到修改后的效果。这对于维护来说是很有优势的。

          我不喜欢代码生成器,不去使用代码生成器,才迫使我想出来了这样的方法,好与不好,这是一种尝试。如果我用代码生成器,“享受”代码生成器带来的好处,那我连尝试的想法都不会有。我怎么会找到更快捷的方式呢?

  • 相关阅读:
    lazarus中objfpc编译模式与delphi编译模式的不同
    TFDUpdateOptions.UpdateNonBaseFields
    protobuf数据类型与delphi数据类型映射
    delphi基于google protobuf开发
    mormot https设置
    基于数据模型的序列
    fastmove+fastcode
    localstack 应用架构
    dremio 21 pdfs 不在支持
    dremio 21 其他一些新特性
  • 原文地址:https://www.cnblogs.com/jyk/p/1494356.html
Copyright © 2020-2023  润新知