Git.Framework 框架随手记--历史原因

 

  Git.Framework 是近几年工作的一些工作经验总结,虽不能和某些知名的框架相提并论,但是还是比较实用的。此框架经过三年多的升级和维护,已经具有较强的实用性,在此记录该框架的使用操作方式,贡献给公司第一线开发的技术人员们,感谢你们所付出的努力。

 

  一. 框架由来

    前几年我都是在互联网公司工作,做什么大型B2B,B2C网站。至于有多大就不提了,但是在其间做开发人员使用的技术的确比较辛苦,那个时候公司使用的技术还比较落后,最起码我是这么认为的,开发效率很低,一层不变的开发模式,Copy到想吐的代码。我是从事.NET技术开发的,当时公司还是使用的.NET2.0开发的,要知道2.0 和 3.0 差别还是挺大的,最起码在语法上。

    据说公司的框架是参考某个大型B2C网站的,据说当时公司某技术君就是从那里面出来的,使用微软企业库(Enterprise Library) , 于是一个B2C网站+ SNS社区 几乎所有的数据访问操作都是写的SQL语句,而且都是配置在某个文件夹的配置文件中。做过B2C或者SNS方面开发的可以想象得到有多少个SQL语句,当时我估计也有好几千个吧。于是我就想在原有的技术框架上改进这个操作,经过世事变迁最终改的体无完肤也就是现在所谓的的框架(Git.Framework)了。

 

  二. 写SQL语句复杂在哪里

    先给大家看看当时我们的SQL语句的写法,以及如何配置:

<dataCommand name="User.UpdateAllBase" database="Git" commandType="Text">
    <commandText>
      <![CDATA[
       UPDATE [Gas_BasicCenter].[dbo].[User_Base]
       SET [UserName] = @UserName
          ,[Email] = @Email
          ,[Password] = @Password
          ,[RegisterDate] = @RegisterDate
          ,[RegisterIp] = @RegisterIp
          ,[Status] = @Status
          ,[RegisterApplicationID] = @RegisterApplicationID
          ,[ActiveDate] = @ActiveDate
          ,[LastLoginDate] = @LastLoginDate
          ,[LastLoginApplicationID] = @LastLoginApplicationID
          ,[RegisterSource] = @RegisterSource
          ,[AuditStatus] = @AuditStatus
          ,[IsLogin] = @IsLogin
          ,[LoginCount] = @LoginCount
          ,[LastLoginIp] = @LastLoginIp
          ,[AuditUser] = @AuditUser
          ,[AuditDate] = @AuditDate
          ,[IsDeleted] = @IsDeleted
          ,[OLDApplicationID] = @OLDApplicationID
          ,[OLDID] = @OLDID
          ,[RowGuid] = @RowGuid
          ,[IMNum] = @IMNum
          ,[Phone] = @Phone
          ,[IsEmailValidate] = @IsEmailValidate
          ,[IsPhoneValidate] = @IsPhoneValidate
          ,[StepNum] = @StepNum
          ,[SaleCode]=@SaleCode
          ,[PasswordIM]=PasswordIM
          ,[ActiveIP]=@ActiveIP
          ,[CompanyType]=@CompanyType
            Where UserId=@UserId
        ]]>
    </commandText>
    <parameters>
      <param name="@UserId" dbType="Int32" direction="Input"/>
      <param name="@UserName" dbType="String" direction="Input"/>
      <param name="@Email" dbType="String" direction="Input"/>
      <param name="@Password" dbType="String" direction="Input"/>
      <param name="@RegisterDate" dbType="DateTime" direction="Input"/>
      <param name="@RegisterIp" dbType="String" direction="Input"/>
      <param name="@Status" dbType="Int32" direction="Input"/>
      <param name="@RegisterApplicationID" dbType="Int32" direction="Input"/>
      <param name="@ActiveDate" dbType="DateTime" direction="Input"/>
      <param name="@LastLoginDate" dbType="DateTime" direction="Input"/>
      <param name="@LastLoginApplicationID" dbType="Int32" direction="Input"/>
      <param name="@RegisterSource" dbType="Int32" direction="Input"/>
      <param name="@AuditStatus" dbType="Int32" direction="Input"/>
      <param name="@IsLogin" dbType="Int16" direction="Input"/>
      <param name="@LoginCount" dbType="Int32" direction="Input"/>
      <param name="@LastLoginIp" dbType="String" direction="Input"/>
      <param name="@AuditUser" dbType="String" direction="Input"/>
      <param name="@AuditDate" dbType="DateTime" direction="Input"/>
      <param name="@IsDeleted" dbType="Int16" direction="Input"/>
      <param name="@OLDApplicationID" dbType="Int32" direction="Input"/>
      <param name="@OLDID" dbType="Int32" direction="Input"/>
      <param name="@RowGuid" dbType="String" direction="Input"/>
      <param name="@IMNum" dbType="String" direction="Input"/>
      <param name="@Phone" dbType="String" direction="Input"/>
      <param name="@IsEmailValidate" dbType="Int32" direction="Input"/>
      <param name="@IsPhoneValidate" dbType="Int32" direction="Input"/>
      <param name="@StepNum" dbType="Int32" direction="Input"/>
      <param name="@SaleCode" dbType="String" direction="Input"/>
      <param name="@PasswordIM" dbType="String" direction="Input"/>
      <param name="@ActiveIP" dbType="String" direction="Input"/>
      <param name="@CompanyType" dbType="Int32" direction="Input"/>
    </parameters>
  </dataCommand>

SQL语句的配置

    情况1:看到上面的配置情况,很多人会联系到java中的某些框架,的确如此!个人对java涉略较少,后来在专门去查找了相关的资料。先不讨论SQL语句配置的格式,一个B2C网站+SNS社区需要多少这样的配置节点,项目在不断的增大,配置的难度到了让人无法接受的程度,而且我们无法知道是否有人已经写过一个同样的SQL语句。有多少人的离开或多或少与这个有关系,那个时候系统出现bug我就是每天盯着屏幕ctrl+h 全局查找这样的配置。

    情况2:SQL语句要每个自己去写,转化还必须要占位符的方式,然后要填充参数(<param name="@UserId" dbType="Int32" direction="Input"/> 也就是这个配置)。当然这些都是手工体力劳动,不难当时的确会写死人,比类文件中直接写SQL还要累。

    情况3: <dataCommand name="User.UpdateAllBase" database="Git" commandType="Text"> 配置项name在全局是唯一的,而系统中有很多个这样的配置文件,在这个文件中你查找不到,并不代表其他的文件没有,要每一个文件都去查找一遍然后才能定义这个name值。 database 这个也存在问题,这个是关联数据库的,因为系统中存在多个数据库,必须关联这个sql在哪个库里面执行。 

    情况4:<parameters><param name="@UserId" dbType="Int32" direction="Input"/></parameters> 参数项的配置太多,特别是表的字段多的时候,修改好烦躁。有时候修改一个字段,有时候修改其中几个字段,要分别写不同的SQL来执行。

    情况N .... 就不多写了,各种问题足以让人抓狂,拿人钱财替人写代码天经地义的事情所以没办法,硬着头皮写。

 

  三. 以上问题的改进

    那个时候自己还是小兵啊,人微言轻的,也不敢提框架不好使,不然大牛会生气,后果很严重。想想也是完成好自己的工作就好了。

    配置问题的解决:

      上面贴出来的这个配置文件,其实一个定义好的标准格式,包括里面的参考类型以及名称都是定义好的,后来我使用CodeSmith自定义模板生成,很快速的结果手工写模板的问题,但是有一个问题就是模板没有那么灵活,我需要指定哪些字段要使用哪些不能使用,不是那么自能,只能全部给我生成出来,不过也算是方便了不少。

    实际问题考虑:

    (1) 登录系统,两个步骤: 1. 查询用户名和密码 2. 查询用户详细信息

    都是使用User表,我们可以查询User表的所有数据,但是往往登录的时候我们只会查询用户名和密码,查询用户详细的时候又不查询密码,甚至还有权限的问题,网络传输的问题。只能查询当前业务操作所需的字段。

SELECT [UserNo],[UserPwd] FROM [dbo].[SysUser]

SELECT [UserNo],[UserCode],[UserName],[UserPwd],[IsDelete] FROM [dbo].[SysUser]

    以上两个SQL语句有区别么,肯定有区别,查询的虽然是同一张表,但是返回的数据量大小不一样,为什么要这么做? 后来做信息化管理系统之后,也就不管这么多了都直接使用 Select * From Table 直接代替了。

    (2) 修改个人资料信息

    

    以前工作的项目图片不好找了,直接以博客园的为例。 假设用户头像,昵称,姓名,联系方式,毕业院校等信息是保持在User表中(当然现在很多信息也有是分表处理的,暂且不谈,这是数据结构设计问题)的。看上面的截图,用户信息的维护每次用户数据的提交并不是提交了所有的个人信息数据,而只是部分提交的。

Update [dbo].[SysUser] Set Picture=@Picture where UserNo=@UserNo

Update [dbo].[SysUser] Set LoginCount=@LoginCount,UserName=@UserName where UserNo=@UserNo

    诸如以上的这种太多的有共性但是又有区别的SQL语句太多了。

    后来使用的方式就是,先将某条数据全部查询出来,封装为一个Entity,然后修改Entity中的某个值,然后提交所有的Entity值,也就是修改表中的每一个字段,虽然处理的方式不好,但是比写N个这样的Sql语句配置省事多了。

 

   四. 如何检查配置项的重复问题

    颇为头疼的就是配置项name值的重复问题,N多个配置文件在某一个文件夹下,而文件夹中又有文件夹,查找不方便。

    软件的作用是什么,这个问题太过于广泛,但是有一点软件能够省人工,这个我是赞同。如何去查找重复项,那么就写一个小程序去区分好了。程序非常简单就是读取所有的配置文件,然后盘点是否有相同的项,这里不必多说,但是这个时候让我学到一个技能,就是如何写VS插件。

    之前写的工具已经不复存在,刚才在网上随便找了一篇文章关于这个的介绍,有兴趣可以参考一下:

    http://blog.csdn.net/clever101/article/details/8733799

 

  五. 实质性的问题如何解决

    以上种种手段都是暂时的解决问题,并没有达到治本的目的。于是自己开始筹划改进公司的技术框架。

    当时公司的技术体系就是这样,基于以前的工作经验,你想要去推翻公司的技术体系然后再重新来过是不太可能的,而且这个想法也是过于天真的,先不说你是否有这个能力,就算你有公司也不会冒这样的风险。

    当然当时我也提过技术框架的改进,当时领导评估风险太大,只能慢慢的去维护,也就是公司不可能专门设计组织或项目来搞这个东西,所以我只能自己业余时间来了。

    1. 数据操作使用ORM是不可避免的方向

      当时推崇过一段时间的Linq to SQL,包括Entity Framework ,也给公司提过,公司坚决的否定了,而后来我也对此嗤之以鼻因为其臃肿度,也不知道我是否理解错了。研究了好长一段时间的Linq to SQL ,Entity Framework 后来也不不再理这个。

      对比了一些较为常见的ORM,无论怎么吹嘘怎么怎么强大但都有其天生的缺陷性,没有一个是万能的。后来我也承认这些东西不可能是万能的,所谓真正好的框架是在实际的业务中提炼出来的,而不是你想怎样就能帮你解决问题的。

      加上要兼容公司原有的技术体系,所以这个只能改进不能重新来过。

    2. 去配置化

      那个时候还年轻啊,听老前辈说配置化如何的牛逼,特别是java程序员,java中的配置化多么牛逼,系统如何的灵活! 现在我始终认为那是一个骗局,要么是我没有理解其精髓,要么他们也就是照书上照本宣科的胡乱说一通。这不是重点,重点是如果我改进一定要去配置化,因为配置已经让我们身处火热之中。

    3. 蛋疼的跨数据库查询

      如果在同一个数据库实例中,两个或者多个数据库跨库查询貌似还比较好解决,如果涉及到跨网络肿么办,貌似没有ORM专门去解决这个问题,或许是我孤陋寡闻了。在公司的改进中我提议是跨库查询还是在内存中去处理,就是多次去查询数据库然后内存整合数据,后来也证明了我还是有点明智的,多数据库分离到不同的服务器上了。

    

  六. 本文小结

    在平时的工作中还有很多类似的问题,不知道是因为自己遇到的东西少了还是其他的原因,都是一些非常低级而又苦恼的问题,真正有什么科研技术的问题我真没有遇到。决定写这个文章只是为了总结一下自己这些年的工作,觉得有很多地方是值得借鉴的。

    1. 在一个技术体系已经成型的团队里面,不要妄想去推翻现有的技术体系,虽然这样的体系问题非常多,多到让你无法接受,你要做的是改进,去提升,而不是抱怨问题太多。"要么忍要么滚" 这是我的格言。

    2. 问题多是一个团队的正常表现,如果没有问题团队也就不需要你了。

    3. 只要是问题肯定就会有解决的办法,如果你自己没有去尝试过,不要轻易去评判别人的对与错,否则就闭嘴。

    4. 刚出道或者刚进公司不要认为领导都是傻逼,如果你有这种想法只能说明你比他们更傻逼,几年前我也站在骂领导是傻逼的行列。

    5. 任何一个公司的技术体系都有值得你去借鉴学习的,只要它摆在那里就不会是垃圾。

 

    如今自己做实施了,虽然程序还写,相比之前心情放松了很多,不是为了丢弃代码,只是有时候该换一种方式去思考或许程序会写的更好一点。

 

    成功的定义永远只有一个,那就是对结果负责!

 

    

时间: 2024-10-23 08:06:45

Git.Framework 框架随手记--历史原因的相关文章

Git.Framework 框架随手记--存储过程简化

在很多的ORM中对存储过程操作都是一个棘手的地方,因为存储过程是一段预编译的代码,其中可以包含很多处理过程.在Git.Framework中也同样存在这样的问题,目前没有能力解决这个问题.但是对于存储过程的一些外围操作目前还是可以支持的. 上一篇文章简单回顾地址,可能对了解本文有益: Git.Framework 框架随手记--SQL配置文件的使用 一. 结构简单说明 在前面操作基本SQL的时候我们已经知道使用对象模型映射其相关的表,一些基本的操作我们都能够实现完成.在很大的程度上完成了抽象工作,在

Git.Framework 框架随手记--ORM条件组合

在上一篇<Git.Framework 框架随手记--ORM新增操作>中简单记录了如何对数据进行删除和修改,其用法都非常简单,在文章中提到了Where()方法,本文将详述Where() 等条件函数.   一. SQL 条件分析 对于SQL每个人应该都很熟悉,这是基础的基础,如果没有使用过SQL的本文可以直接忽略了.先简单看看一个SQL语句,我们根据SQL语句的规则理解Where()方法 SELECT [ID],[UserName],[PassWord],[UserCode],[RealName]

Git.Framework 框架随手记--SQL配置文件的使用

前面几篇文章讲到了如何使用框架进行简单结构的增删改查操作,由于个人能力有限在对于复杂的SQL操作面前也是无能为力,只能自己动手来写SQL语句.在Git.Framework中提供了一个公共的接口来直接操作SQL语句. 一. SQL配置文件的结构简介 在这个框架中提供了单独的配置文件用于来管理SQL语句,当然也可以不用配置文件.使用SQL配置文件系统在启动的时候会直接将SQL配置文件转化为Command对象缓存,而不用后期再去创建,这是一个比较不错的优势.下面先看看SQL配置文件的结构 <dataO

Git.Framework 框架随手记--ORM查询数据集合 二

一.  分组查询 在SQL中使用Group By 来对数据分组,在实际中分组中一般与聚合函数一并使用.在Git.Framework中提供了相应的分组方法 DataTable Group(T entity); DataTable Group(T entity, bool isOpenTrans); IEnumerable<System.Linq.IGrouping<TKey, T>> Group<TKey>(T entity, Func<T, TKey> ke

Git.Framework 框架随手记--IIS7运行序列化问题

客户反馈系统又登录不了,这是最近几次连续出现相同的问题,从日志反应情况来看: 日志级别:[info] 日志位置:Git.Framework.Resource.ResourceManager 日志时间:2014/12/3 9:08:30 日志内容:反序列化异常:Unable to generate a temporary class (result=1). error CS1567: Error generating Win32 resource: 另一个程序正在使用此文件,进程无法访问. 日志级

Git.Framework 框架随手记--ORM新增操作

本篇主要记录具体如何新增数据,废话不多说,开始进入正文. 一. 生成工程结构 上一篇已经说到了如何生成工程结构,这里在累述一次. 1. 新建项目总体结构 使用VS新建项目结构,分层结构可以随意.我们使用的结构如下: 2. 引入配置文件相关 Configs文件夹中的配置文件,其目录结构如下图: 以上几个文件为必须的,除了最下面的画红线的为自定义可以修改,具体配置项内容可以参考前面几篇文章.然后再web.config定义如下配置: <appSettings> <add key="D

Git.Framework 框架随手记--ORM查询数据集合 一

本文记录Git.Framework之ORM中最为浓墨重彩的一篇,查询集合.根据自己做的项目统计这个是使用频率最高的一个.   一. 查询集合方法简介 (1)List<T> GetList(); (2)List<T> GetList(bool isOpenTrans); (3)List<T> GetList(T entity); (4)List<V> GetList<V>(T entity) where V : class, new(); (5)L

Git.Framework 框架随手记--ORM查询返回实体对象

使用ORM有一个优势,可以通过某种机制将数据库中的数据转化为自己想要的对象形式数据.本章记录一下如何使用Git.Framework返回实体对象   一. Git.Framework 中提供的方法 在Git.Framework中有七个方法可以返回实体对象,先简答的看看这里的方法描述 (1) T GetSingle(int id); (2) T GetSingle(object value); (3) T GetSingle(T entity); (4) V GetSingle<V>(T enti

Git.Framework 框架随手记--准备工作

前面已经提到过了本框架的由来,时至今日该框架已经和最初版本有了天壤之别.因为仍有部分代码是采用原有的框架,所以本框架也算不上原创,只是在原有的基础上不断的改进,所以希望了解此框架的人不要过多的指责. 一. 配置数据库连接 在该框架中自定义了一个配置文件Database.config, 这个配置文件的根节点为<databaseList></databaseList>, 其可以包含多个子节点用于配置数据库的配置连接,具体代码如下: <?xml version="1.0&