`
saybody
  • 浏览: 902953 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

C#基础系列:实现自己的ORM(构造我自己的ORM)

阅读更多

构造我自己的ORM

通过前面两章的描述,我相信很多朋友都已经明白我了下面将要讨论到的ORM的实现方法了,那就是根据自定义Attribute来定义O/R Mapping规则,然后通过反射来动态获取此规则,动态构造SQL语句。
由于这个小东西(ORM)出生在深圳,所以我想来想去,她应该有个深圳的名字,所以我就叫她“MiniORM”。不知道各位认为如何?
MiniORM采用的是ONE_INHERIT_TREE_ONE_CLASS(一个继承树对应于一个表)的结构,虽然这种结构容易导致数据冗余,但是这种结构很简单。另,本MiniORM 仅仅考虑一个表一个PK,一个FK的情况。

MiniORM结构如下,为了更便于理解和使用,我使用了3个类:
1、OrmWriter:负责将实体对象(比如前面章节说的Person)插入数据库和修改数据库中对应的记录。
2、OrmRemover:负责根据实体对象,删除指定的记录;
3、OrmReader:负责根据实体对象,读取指定的记录;

上面就是MiniORM的3个主要类。下面我们就详细地根据前面的描述一步步构造她。我们这里还是以前面说的Person为例进行说明。

通过本系列第一章,我们知道,对象不但存在继承关系,特别在实际的应用中还存在包含关系,比如一个Person包含两个Hand(手)类,包含一个Head(头)类等,我们的Person在数据库中应该有一个ID,为了更加方便使用和讨论,此ID在MiniORM中是一个int以及自动增长类型(ID INDENTITY(1,1))。这些都是我们的MiniORM应该考虑的范围。
我们对我们的Person做修改:

  1. [DataObjectAttribute("Person")]
  2. publicclassPerson
  3. {
  4. privateint_ID;
  5. privatestring_Name;
  6. privateint_Age;
  7. privatestring_Sex;
  8. privateHead_Head;
  9. privateHand_LeftHand;
  10. privateHand_RightHand;
  11. publicintID
  12. {
  13. get{return_ID;}
  14. set{_ID=value;}
  15. }
  16. publicHeadHead
  17. {
  18. get{return_Head;}
  19. set{_Head=value;}
  20. }
  21. publicHandLeftHand
  22. {
  23. get{return_LeftHand;}
  24. set{_LeftHand=value;}
  25. }
  26. publicHandRightHand
  27. {
  28. get{return_RightHand;}
  29. set{_RightHand=value;}
  30. }
  31. [DataFieldAttribute("name","NvarChar")]
  32. publicstringName
  33. {
  34. get{returnthis._Name;}
  35. set{this._Name=value;}
  36. }
  37. [DataFieldAttribute("age","int")]
  38. publicintAge
  39. {
  40. get{returnthis._Age;}
  41. set{this._Age=value;}
  42. }
  43. [DataFieldAttribute("sex","NvarChar")]
  44. publicstringSex
  45. {
  46. get{returnthis._Sex;}
  47. set{this._Sex=value;}
  48. }
  49. }

你可能又发现了一个问题,就是在我们修改后的Person中,增加了LeftHand,RightHand以及Head,可是这三个都属于类啊,这个怎么能够保存到数据库中呢?并且使用我们前面的DataFieldAttribute是没有办法描述的啊。另外还增加了个ID,又怎么来标志这个是自动增长的int型PK呢?当然了能够到这里你就发现这些问题那是相当的不错了。如果前面就动手的人,估计考虑的还是修改我们的DataFieldAttribute让它能够对这些东西进行区别。比如在DataFieldAttribute中再增加一个属性用于区别哪个是ID属性,哪个是对象类型(比如Hand)属性。这当然是好的,只不过这样做导致我们的代码极其丑陋。最好的办法还是另外增加一个Attribute。当然了,我是为了更加方便的构造SQL语句,我做的不是很好。

1、怎么表示实体类对应的数据库表的PK和FK?
为了更方便的实现,MiniORM中标志一个实体类的PK和FK都是在DataObjectAttribute中来做(其实最好的办法还是另外增加个比如PKAttribute和FKAttribute,不过这个留给其它人去做吧)。如下,DataObjectAttribute第一个参数表示对应的数据库表,第二个参数表示PK,第三个参数表示FK:

  1. [DataObjectAttribute("Person","ID","")]
  2. publicclassPerson
  3. {
  4. ......
  5. }

2、怎么标志字段是Indentity(自动增长)?
在DataFieldAttribute中增加了个属性,用于标志某个字段是否自动增长的字段。这些都是我个人懒做的,其中,第二个参数标志ID是Identity类型

  1. [DataFieldAttribute("ID",true)]
  2. publicintID
  3. {
  4. get{return_ID;}
  5. set{_ID=value;}
  6. }

3、怎样标志字段是类对象(比如Person中的Hand,当然复杂点的对象,可能包含子对象列表)?
由于MiniORM提供的是一个类似框架的东西,所以不应该受到实体类的限制,所以对于类对象字段,我们应该能够描述此对象所在的程序集,命名空间,类名,这样我们才可以运行时创建该对象。

  1. publicclassSubDataObjectAttribute:Attribute
  2. {
  3. privateSubDataObjectFieldType_FieldType;
  4. privatestring_AssemblyName;
  5. privatestring_NamespaceName;
  6. privatestring_ClassName;
  7. publicSubDataObjectAttribute(SubDataObjectFieldTypefieldtype,stringassemblyname,stringnamespacename,stringclassname)
  8. {
  9. this._FieldType=fieldtype;
  10. this._AssemblyName=assemblyname;
  11. this._NamespaceName=namespacename;
  12. this._ClassName=classname;
  13. }
  14. ///<summary>
  15. ///本记录对应的FieldType
  16. ///</summary>
  17. publicSubDataObjectFieldTypeFieldType
  18. {
  19. get{return_FieldType;}
  20. }
  21. ///<summary>
  22. ///本记录对应的AssemblyName
  23. ///</summary>
  24. publicstringAssemblyName
  25. {
  26. get{return_AssemblyName;}
  27. }
  28. ///<summary>
  29. ///本记录对应的NamespaceName
  30. ///</summary>
  31. publicstringNamespaceName
  32. {
  33. get{return_NamespaceName;}
  34. }
  35. ///<summary>
  36. ///本记录对应的ClassName
  37. ///</summary>
  38. publicstringClassName
  39. {
  40. get{return_ClassName;}
  41. }
  42. }

其中SubDataObjectFieldType是一个枚举类型,因为我们的子对象可能是单独的对象比如Person.Head也可能是一个列表(List)。所以我增加了这个枚举类型,用于做标志。

  1. publicenumSubDataObjectFieldType
  2. {
  3. Object,
  4. ///<summary>
  5. ///本字段属于List类型,直接遍历
  6. ///</summary>
  7. List,
  8. }

当然了,这里的子对象列表可能是ArrayList,HashTable等等,你都可以根据自己项目中实际使用到的类型来做相应的修改。

4、怎么控制某个字段在表中不能重复?
比如我们要控制Person.Name不能重复,如果你新增的时候发现重复要提示。那我们也通过增加一个Attribute的形式来实现。这个Attribute很简单,没有任何方法和属性。

  1. publicclassDataFieldNotDoubleAttribute:Attribute
  2. {
  3. }

5、怎样做事务处理?
事务处理是每个底层框架都应该考虑到的问题,在.NET中我们有两种方式来进行事务处理,一种是使用COM+,这是最好的方法,不过性能上比较欠缺,另外这东西配置很麻烦,当你数据库安装在另外一太服务器上的时候,往往出现无法使用的问题,我曾经就被这东西折腾够呛,所以我干脆就不用他了,不过还是介绍下语法,通过使用TransactionScope就可以很好的使用com+提供的事务处理,代码相当的简洁,优美,只可惜啊!天使的面孔,魔鬼的心。

  1. publicvoidfunction1()
  2. {
  3. using(System.Transactions.TransactionScopescope=newSystem.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required))
  4. {
  5. function2();
  6. }
  7. }
  8. publicvoidfunction2()
  9. {
  10. using(System.Transactions.TransactionScopescope=newSystem.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required))
  11. {
  12. //DoSomething();
  13. }
  14. }

另外一种方法就是使用SqlTransaction:

  1. using(SqlConnectionconn=newSqlConnection(ConnectionStr))
  2. {
  3. conn.Open();
  4. SqlTransactiontrans=conn.BeginTransaction();
  5. //DoSomething();
  6. trans.Commit();
  7. }

不过遗憾的是这种方式不能实现事务嵌套,所以只能通过将trans作为参数进行传递来实现事务处理。

经过上面一系列的修改后,我们的Person成了什么样子了?

  1. [DataObjectAttribute("Person","ID","")]
  2. publicclassPerson
  3. {
  4. privateint_ID;
  5. privatestring_Name;
  6. privateint_Age;
  7. privatestring_Sex;
  8. privateHead_Head;
  9. privateHand_LeftHand;
  10. privateHand_RightHand;
  11. [DataFieldAttribute("ID",true)]
  12. publicintID
  13. {
  14. get{return_ID;}
  15. set{_ID=value;}
  16. }
  17. [SubDataObjectAttribute(SubDataObjectFieldType.Object,"Person","Person","Head")]
  18. publicHeadHead
  19. {
  20. get{return_Head;}
  21. set{_Head=value;}
  22. }
  23. [SubDataObjectAttribute(SubDataObjectFieldType.Object,"Person","Person","Hand")]
  24. publicHandLeftHand
  25. {
  26. get{return_LeftHand;}
  27. set{_LeftHand=value;}
  28. }
  29. [SubDataObjectAttribute(SubDataObjectFieldType.Object,"Person","Person","Hand")]
  30. publicHandRightHand
  31. {
  32. get{return_RightHand;}
  33. set{_RightHand=value;}
  34. }
  35. [DataFieldAttribute("name","NvarChar")]
  36. publicstringName
  37. {
  38. get{returnthis._Name;}
  39. set{this._Name=value;}
  40. }
  41. [DataFieldAttribute("age","int")]
  42. publicintAge
  43. {
  44. get{returnthis._Age;}
  45. set{this._Age=value;}
  46. }
  47. [DataFieldAttribute("sex","NvarChar")]
  48. publicstringSex
  49. {
  50. get{returnthis._Sex;}
  51. set{this._Sex=value;}
  52. }
  53. }

当然了对于Person这样的实体类,我们完全可以自己写代码自动生成工具来弄,然后再做很小的修改就可以了,这样的工具实现简单,我就不讨论了。
好了,关于我的MiniORM我就讨论到这里了,其它的请看代码吧。

ORM虽然是好东西,但是也存在很多方面的不足,首先我们能够做到的是将大部分的数据库操作交个ORM来做。另外少部分还是需要我们自己写SQL的。单大部分的工作的分离可以为我们节约大量的时间(也就是所谓的20/80原则,80%的教给ORM来处理,20%的自己做,当然很好了)。另外通过将这些相同的流程教给ORM来处理,可以避免很多的疏忽导致的失误(比如不小心把某个Insert,Update,Delete语句弄错了什么的)。
最主要的缺点当然是性能问题,特别是我的MiniORM,全部采用反射来获取映射规则,从而导致性能上更多的下降,不过我们了解方法以后是很容易通过动态生成代码,动态编译的方式来减少这部分的性能损失的。另外某些部分的代码显得有些臃肿,特别是把判断是否Indentity这样的代码放DataFieldAttribute中来处理(这个完全可以象DataFieldNotDoubleAttribute一分开处理的样)等等。

相关文章:

C#基础系列:实现自己的ORM(ORM的基础概念)

C#基础系列:实现自己的ORM(反射以及Attribute在ORM中的应用)

C#基础系列:实现自己的ORM(MiniORM的测试代码)

源代码下载

分享到:
评论

相关推荐

    基于C#实现的轻量级ORM类库源代码

    3. **查询构造器**:为了减少硬编码SQL,ORM通常会有一个查询构造器,允许开发者用C#代码构建SQL查询,然后由ORM自动生成对应的SQL语句。 4. **实体类**:这些是表示数据库表的C#类,通常包含与数据库字段相对应的...

    C#发现之旅:使用反射和特性构造自己的ORM框架实用.pdf

    标题中提到的"C#发现之旅:使用反射和特性构造自己的ORM框架实用",主要讨论的是如何利用C#语言中的反射和特性这两个高级特性来构建一个自定义的ORM框架。反射是.NET框架提供的一种强大的动态类型处理能力,它允许在...

    C# ORM程序及实体生成工具

    标题提到的"C# ORM程序"是指基于C#语言实现的ORM框架,它可能包含一系列类库和工具,用于与多种类型的数据库(MySQL, SQLite, SQLServer, Oracle, Access)进行交互。ORM工具的核心功能包括但不限于数据查询、事务...

    sqlite3的ORM框架

    5. **查询构造器**:为了灵活地执行复杂的查询,ORM框架通常会提供一个查询构造器,允许开发者通过链式调用来构建SQL语句。这可以是基于表达式的API,也可以是类似于SQL的语法。 6. **事务管理**:在处理多条数据库...

    简单高效的ORM框架

    ORM,全称Object-Relational Mapping,即对象关系映射,是一种编程技术,用于将关系数据库的数据模型映射到面向对象的编程语言中。在现代软件开发中,ORM框架扮演着重要的角色,它使得开发者无需关注底层SQL语句,就...

    C# 通过反射初探ORM框架的实现原理(详解)

    C# 通过反射初探ORM框架的实现原理 在本文中,我们将探讨C# 通过反射初探ORM框架的实现原理。ORM框架是Object-Relational Mapping的缩写,主要用来实现对象和关系数据库之间的映射。在Java中,我们经常使用Mybatis...

    C#根据模型动态生成SQL和DBHelper

    在C#中,可以使用System.Data.SqlClient命名空间下的SqlClient类库来实现这一目标。例如,可以使用SqlCommand对象创建SQL命令,通过StringBuilder或String.Format方法动态构造SQL字符串。此外,可以利用Linq-to-SQL...

    C#基础知识案例

    本“C#基础知识案例”旨在深入浅出地介绍C#的关键概念和技术,帮助初学者快速掌握这门语言。 1. **基础语法** - 变量声明:C#中的变量需要先声明后使用,支持多种数据类型,如int、double、string等。 - 控制结构...

    C#其他分页实现源码参考Demo'.rar

    总之,"C#其他分页实现源码参考Demo"可能包含了非标准的分页实现方式,通过对这个Demo的学习,开发者可以了解更多的分页策略和技巧,提升自己的C#编程能力。在实际项目中,选择适合的分页方式和优化手段,能有效提高...

    一个基于C#实现的通用生成后台数据访问层的类库源码程序

    1. C#编程基础: - 类与对象:类库中的核心是各类,如数据访问接口(IRepository)、数据上下文(DbContext)等,它们通过面向对象的方式封装了数据库操作。 - 构造函数:用于实例化对象,可能包含初始化数据库...

    反射的应用 一个简单的ORM.rar

    总结来说,这个简单的ORM示例利用了C#的反射机制,动态地获取类型信息并构造SQL语句,实现了基本的数据库操作。虽然实际的ORM框架如NHibernate、Entity Framework等提供了更复杂的功能和优化,但这个示例为我们理解...

    通俗易懂C#课件是c#初学者及有一定其它编程语言基础的朋友学习的好材料

    C#是一种由微软公司开发的面向对象的编程语言,它被广泛应用于...通过学习以上知识点,并结合"通俗易懂C#课件"中的实例和练习,无论是初学者还是有一定基础的学习者,都能逐步精通C#,为自己的编程技能树添砖加瓦。

    C#&&.NET讲义

    这份讲义涵盖了从基础到高级的C#语法、.NET框架的核心概念,以及如何利用它们进行实际项目开发。以下是基于课件内容的关键知识点概览: 1. C#基础: - 变量和数据类型:理解基本的数据类型(如int、string、bool等...

    C#数据库编程实战与讲解

    学习如何构造SELECT、INSERT、UPDATE和DELETE语句是基础,更高级的包括JOIN、子查询和存储过程。 3. **数据访问层(DAL)**: 数据访问层是应用程序和数据库之间的桥梁。在C#中,可以创建类库来封装数据库操作,使得...

    一个基于C#的简单有效的实现数据库复杂组合查询的管理工具源代码

    例如,通过linq-to-sql,可以使用类似C#的查询语法构造复杂的数据库查询,结合lambda表达式和 LINQ 查询运算符,实现动态组合查询。 在处理复杂组合查询时,QueryTool可能会使用到SQL的JOIN、WHERE、GROUP BY、...

    [开发工具] Telerik OpenAccess ORM Q3 2012 SDK

    ORM工具允许开发者使用高级编程语言(如C#或VB.NET)来操作数据库,无需直接编写SQL语句,提高了开发效率并降低了代码与数据库间的耦合度。 在【Telerik OpenAccess ORM Q3 2012 SDK】中,Q3 2012.3 1012 表示该...

    C#项目实训教程课件[于润伟]

    这套教程旨在将理论学习与实际操作相结合,帮助学习者在掌握C#基础知识的同时,提升项目开发的实践能力。下面将详细阐述本教程涵盖的知识点。 一、C#基础 1. C#语言概述:介绍C#的历史、特点、应用领域以及它在.NET...

    C#基础加强

    ### C#基础加强知识点概述 #### 一、C#及.NET平台基础 - **.NET学习路线**: .NET是一个由微软开发的软件框架,旨在提供一个一致的编程环境,简化跨平台的应用程序开发过程。学习路线包括理解.NET的核心组件、语言...

    c#入门经典书—源码

    1. **基本语法**:C#的基础始于它的语法结构,包括变量声明、数据类型(如整型、浮点型、字符串和布尔型)、运算符(算术、比较、逻辑等)、流程控制(如if语句、switch语句、for循环和while循环)。 2. **类与对象...

    C#深入浅出全接触C#深入浅出全接触

    《C#深入浅出全接触》是一本专为C#初学者及有一定基础的开发者编写的教程,旨在全面解析C#编程语言的核心概念和技术。在深入理解C#的过程中,本书涵盖了从基本语法到高级特性的全方位知识,帮助读者建立起扎实的编程...

Global site tag (gtag.js) - Google Analytics