利用抽象、多态实现无反射的绿色环保ORM框架-创新互联

最近一直在忙新公司的基础库建设,对系统架构、开发框架及快速开发平台的设计实施都积累了一定的实践经验。

创新互联专注为客户提供全方位的互联网综合服务,包含不限于成都网站设计、成都做网站、天涯网络推广、小程序开发、天涯网络营销、天涯企业策划、天涯品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们大的嘉奖;创新互联为所有大学生创业者提供天涯建站搭建服务,24小时服务热线:13518219792,官方网址:www.cdcxhl.com

一般的中小型的软件开发公司,如果按照技术储备来衡量软件项目的技术含量的评定依据是可行的。但如果光是按照人头来衡量软件的技术含量是不可靠的。所以我们在选择跳巢的时候是选择大公司还是选择有技术含量的公司要根据自己的职业规划来。(本人最近体会到的一点跳巢经验分享给大家)

由于我现有单位技术部门刚刚成立不久,需要一些基础的开发框架,ORM当然是跑不了的。在后面的文章中我将陆续写下我在建设基础框架中的一些实践检验,里面可能包括对UI层的封装、基础控件的封装等等。我就废话少扯了,进入主题。

这篇文章的重点是无反射的ORM框架,为什么会有这样的想法?其实前不久群里的朋友就问了一些问题,他们在构建自己的ORM框架的时候频繁的在使用反射来编写功能。从跟他们的交流上来看他们似乎很喜欢使用反射来写功能,但是没有仔细的研究过ORM框架的作用是在系统架构的哪个位置,在对性能要求十分严格的情况下反射会有点无能为力。

反射的好处当然是毋庸置疑的,一些技术稍微好点的或者大牛们通常会用动态编译的技术来平滑的过度这个系统最重要的性能瓶颈点。我总觉的可以用高层的抽象和约定来解决这个ORM使用反射的问题。下面我们来分析一下通常ORM框架为什么需要用反射,反射的目的是什么。[王清培版权所有,转载请给出署名]

ORM中反射的目的是什么?

当然我们这里讨论的是最普通的问题也是必须的问题。

ORM框架的种类形态各异,不同的公司不同的ORM实现。其实目的是为了能有一套属于自己公司的开发框架,这不是技术所定而是公司高层领导所要求的。(我们没有说话的权利,为了保住饭碗,我们只能听从指挥)

但是大部分的ORM框架的设计思想和实现思路都离不开那几点的“思维实现约束”。我为什么要说“思维实现约束”,这也是我们程序员的一些通病之一吧,都喜欢用复杂的技术。不管三七二十一用了心里舒服。这是好事,为了练习技术可以理解。没有这份好奇心这份激情我们也很难走到专家的位置。

目的之一:为了表达实体与表的对应关系

ORM是实体与表的一种映射关系,逐渐被发展为一种复杂的技术实现模型。

在传统的分层架构中,在实体的定义上都会使用一个特性来标记该实体所表示的表名称是什么。如:

[Serializable()]

[HZ.Table(TableName = "member")]

public class Member{}

特性HZ.Table中的属性TableName来保存静态的表名,在ORM中通过获取对象的类型然后反射出该类型的特性元数据。然后读取相关成员属性值,作为拼接SQL语句的必备条件。

目的之二:为了表达属性与字段的对应关系及一些主、外键

ORM中将实体的属性映射成数据库中表的字段,一般通过两种方式来表达这中关系。

第一种:通过属性特性来表示该属性代表的字段名称;

[HZ.Column(PrimaryKey = true,ColumnName=”MemberId”)]

public string MemberCode { get; set; }

第二种:直接通过属性名称来表示字段的名称;

public string MemberId { get; set; }

目的之三:获取实体属性中的值

在进行插入或更新的时候需要获取实体中的属性的值,这个时候只能使用反射的方式获取到属性的值,然后拼接插入或更新语句。

目的之四:设置实体属性的值

通过实例化泛型对象,然后反射对象的属性通过SetValue方法设置属性的值。

简结:这几点是最常用的,可能还包括其他复杂的功能,这里我就不涉及了。上面这几点都是通过反射获取实体的信息,不管是增、删、改、查都需要反射。尤其是对于查询数据来说,如果是大数据量的查询性能问题很吓人。

通过抽象、多态设计不需要特性的ORM实体

大部分ORM框架是需要代码生成器做支持的,不是所有的代码都是需要程序员手动去敲的,可以通过一些模板引擎类的代码生成器,编辑好自己的模板然后生成大部分的实体代码。包括.NET里面的EntityFramework、LinqToSql也是用IDE集成的代码生成器。

所以这里就会涉及到对企业代码生成器的考虑,这里就先不扯了,后续文章我们再来针对性讨论。

那么我们先来讨论如何设计实体结构,让它能包含我们ORM所需要的必备信息。其实我们的思路稍微转变一下利用抽象来解决问题。提高抽象层次,将实体视为两个层面。顶层抽象类被ORM使用,子类被调用者使用。

图:

利用抽象、多态实现无反射的绿色环保ORM框架

我们的要求就是ORM中不能存在一个反射的代码。所以我们约定了BasicEntityObject抽象类,通过定义顶层抽象基类来包含子类所要用到的一些属性信息。

我们看一下抽象类中包含了哪些东西。

  1. using
  2. using
  3. using
  4. using
  5. namespace
  6. publicabstractclass
  7. /// 
  8. /// 实体对象对应数据库中的表名
  9. /// 
  10. privatestringstring
  11. /// 
  12. /// 受保护字典:实体类中对应数据库表中主键的属性和属性类型
  13. /// 
  14. protectedstringstringnewstringstring
  15. /// 
  16. /// 用于实体子类设置当前子类对应数据库中的表名
  17. /// 
  18. protectedstring
  19. getreturn
  20. set
  21. /// 
  22. /// 客户代码获取当前实例对应ORM中的表名
  23. /// 
  24. publicstring
  25. getreturn
  26. /// 
  27. /// 用于实体子类设置当前实例的属性值
  28. /// 
  29. /// 
  30. /// 
  31. protectedobjectthisstring
  32. getreturnthis
  33. setthis
  34. /// 
  35. /// 设置实例的属性值
  36. /// 
  37. /// 属性名称
  38. /// 属性值
  39. publicvoidstringobject
  40. ifthis
  41. this
  42. /// 
  43. /// 获取实例的属性键值队
  44. /// 
  45. /// 
  46. public
  47. getreturnthis
  48. /// 
  49. /// 获取实例的主键信息
  50. /// 
  51. public
  52. getreturn
  53. protectedabstractvoid

其实代码很简单,就是为了将子类的属性值保存到基类中来,让子类只是一个空壳子。

  1. publicclass
  2. /// 
  3. /// 唯一主键
  4. /// 
  5. publicstring
  6. getreturnthis"CID"asstring
  7. setthis"CID"
  8. /// 
  9. /// 车牌号
  10. /// 
  11. publicstring
  12. getreturnthis"CarBanrdCode"asstring
  13. setthis"CarBanrdCode"
  14. /// 
  15. /// 
  16. /// 
  17. publicstring
  18. getreturnthis"CarCode"asstring
  19. setthis"CarCode"
  20. /// 
  21. /// 
  22. /// 
  23. publicstring
  24. getreturnthis"DriverName"asstring
  25. setthis"DriverName"
  26. /// 
  27. /// 联系电话
  28. /// 
  29. publicstring
  30. getreturnthis"Mobile"asstring
  31. setthis"Mobile"
  32. /// 
  33. /// 车型
  34. /// 
  35. publicstring
  36. getreturnthis"CarType"asstring
  37. setthis"CarType"
  38. /// 
  39. /// 购车日期
  40. /// 
  41. public
  42. getreturnthis"BuyDateTime"as
  43. setthis"BuyDateTime"
  44. /// 
  45. /// 所属中心编号。外键
  46. /// 
  47. publicstring
  48. getreturnthis"AttachCenter"asstring
  49. setthis"AttachCenter"
  50. /// 
  51. /// 所属区部编号。外键
  52. /// 
  53. publicstring
  54. getreturnthis"AttachSection"asstring
  55. setthis"AttachSection"
  56. /// 
  57. /// 所属站点编号。外键
  58. /// 
  59. publicstring
  60. getreturnthis"AttachStop"asstring
  61. setthis"AttachStop"

那么中间的类是干嘛用的呢,是为了将初始化隔离在基类中;

  1. [Serializable()]  
  2. publicclass
  3. public
  4. this"Tb_Car"
  5. /// 
  6. /// 唯一主键
  7. /// 
  8. this"CID"null
  9. /// 
  10. /// 车牌号
  11. /// 
  12. this"CarBanrdCode"null
  13. /// 
  14. /// 
  15. /// 
  16. this"CarCode"null
  17. /// 
  18. /// 
  19. /// 
  20. this"DriverName"null
  21. /// 
  22. /// 联系电话
  23. /// 
  24. this"Mobile"null
  25. /// 
  26. /// 车型
  27. /// 
  28. this"CarType"null
  29. /// 
  30. /// 购车日期
  31. /// 
  32. this"BuyDateTime"null
  33. /// 
  34. /// 所属中心编号。外键
  35. /// 
  36. this"AttachCenter"null
  37. /// 
  38. /// 所属区部编号。外键
  39. /// 
  40. this"AttachSection"null
  41. /// 
  42. /// 所属站点编号。外键
  43. /// 
  44. this"AttachStop"null
  45. /// 
  46. /// 实体类 重写实体基类添加主键信息方法,主键数据类型首字母要大写
  47. /// 
  48. protectedoverridevoid
  49. "CID""string"

通过这种层次的抽象可以很好的规避特性带来的性能问题。在ORM中我们的泛型方法都是约束实体为BaseEntityObject类型,然后所有的信息包括主键、字段、数据类型都能够通过多态的方式获取到。

ORM通过实例化一个对象的实例然后将其缓存起来,作为后续使用。而不需要频繁的实例化中间对象带来的性能问题。

其实大部分的代码都是可以通过代码生成器生成的,我们也正在为公司开发符合自己公司产品的代码生成器,包括对业务代码的高度抽象、业务建模后的代码生成。

当然该篇文章只是简单的讲解了一下核心的内容,也算是抛砖引玉吧。希望对大家来说有点启发作用。[王清培版权所有,转载请给出署名]

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


网站栏目:利用抽象、多态实现无反射的绿色环保ORM框架-创新互联
URL网址:http://pwwzsj.com/article/deijid.html