ORM理解
在上一篇文章中,介绍了“框架”这个概念。在实际工作中,会用到各种各样的框架,今天介绍的是一类非常重要的框架 —— ORM。ORM的全称是 Object-Relational Mapping,即“对象-关系映射”。本文就来介绍一下ORM的概念以及它的具体作用。首先从基础的知识开始说起。
CRUD —— 增、删、改、查
对于绝大多数Web系统或者信息系统系统的开发,或者说信息系统开发中的大多数任务,从原理来说并不复杂。这种开发又有一个名称叫做“CRUD”开 发。CRUD就是信息系统中最常见的4种操作“Create / Read / Update / Delete”—— 创建、读取、更新和删除这4种操作。
例如,我们要开发一个BBS论坛,那么显然我们操作的对象是“帖子”,我开发的系统必须要能够实现“发贴(Create)”、“浏览(Read)帖子”、“编辑(Update)帖子”以及“删除(Delete)帖子”这几个基本操作。
事实上,如果仔细想一下,你所使用的各种系统,都是这4个操作,不同的系统的区别就是CRUD操作的对象和规则不同。比如一个博客系统的CRUD的 对象是文章、一个网上商店系统,CRUD的对象就更复杂一些,包括各种商品、订单等等对象。但是无论这些对象是什么,归根到底要做的,总体上就是CRUD 这4个操作,通常也称为“增删改查”操作。
“增删改查”是4种操作,那么这些操作的对象是什么呢?就是各种数据,比如论坛系统中的帖子、网上商店中的商品和订单等等,那么数据在哪里呢?在两 个地方 —— “内存”和“数据库”:大多数时间,数据就存储在数据库里,静止不动;而在需要对数据进行操作的时候,就把数据读入到内存中,操作完以后,在存回数据库。 因此,下面就来谈谈“数据库”。
数据库与关系模型
计算机最初的主要用途是计算,被称为计算机之父的冯诺依曼,在上世纪40年代,投入很大精力研制计算机,目的就是为了给研制原子弹的曼哈顿计划提供 计算工具。随后,计算机的用途逐渐转向事务处理,也就是处理和存储大量的数据,例如IBM一直是计算机领域的先锋。事实上IBM在计算机发明之前很多年, 就开始长期为美国政府、保险公司等大型机构提供打孔机等商用机器,在计算机出现以后,IBM的第二代领导人敏锐地意识到了计算机将会给整个社会带来的巨大 影响,成功地实现了向计算机业务的转型。为了更有效地处理和存储数据,科学界也经过了好几个阶段的探索,其间提出了若干不同的数学模型,最终以“关系代 数”为理论基础的“关系数据库”成为了数据存储方案的主流模型。
1970年,IBM的研究员,有“关系数据库之父”之称的 Edgar Codd 博士发表了题为“大型共享数据库的关系模型”的论文,文中首次提出了数据库的关系模型的概念,奠定了关系模型的理论基础。在随后的几十年里,关系数据库日 益成熟。今天常用的数据库管理系统,包括 Orcale、SQL server、Access 等等,都是“关系数据库”的产品。
关系数据库的核心,就是通过一系列的范式理论描述的“关系模型”,这个模型的形式化描述,并非几句话可以说清。对于没有在课堂上完整学习过“数据库”这门课程的读者,建议找一本大学教材,细细地读一读,会对背后的原理有更深入的理解。
这里只能简单地解释一下。在“关系模型”中,用一个多元组描述一个实体对象:所谓多元组,就是(x, y, z)这样的形式。例如,描述一个人,可以用(张三, 男,65kg, 1.75m)这样一个多元组来表示。每一个“元”表示的是这个人的某一个“属性”。如果需要表示一群人的集合,就把一系列的同样形式的多元组竖直方向摞起 来,形成一个二维表格,每一行表示一个人。这就是关系数据库的基本模型。一个数据库,就是由很多个这样的表组成的。例如下面的示例表示了这样的一个表。
(张三, 男,65kg, 1.75m)
(李四, 女,60kg, 1.65m)
(王五, 女,55kg, 1.55m)
(赵六, 男,75kg, 1.85m)
为了方便在程序中操作数据库中的数据,1974 年由 Boyce 和 Chamberlin 和提出了 SQL(SQL(Structured Query Language),即“结构化查询语言”。SQL 是一个通用的、功能极强的关系数据库语言。配合关系数据库,SQL发挥巨大的作用,时至今日,SQL也是每一个程序员都必须要掌握的一门语言。通过 SQL 可以方便地完成在数据库中增删改查数据的任务。
“对象模型”Vs“关系模型”
由于信息系统的数据最终都是存储在数据库中,因此我们在写程序的时候,最终任务就是通过使用 SQL 来进行 CRUD 操作。对于一些十分简单的系统,通常是我们首先建立好数据库中的各个数据表,然后在程序中嵌入 SQL 语句,需要浏览数据库中的内容时,就是用 SQL 中的查询语句,读取出内容,然后再通过不同的语言显示在界面上。比如如果用 VB 或者 Delphi,就可以把结果显示在 Windows 窗口中;如果使用 ASP.NET,就可以把数据显示在浏览器的 HTML 页面中。
上面的方法简称为“数据库驱动开发”,是以数据库操作为核心的。事实上即使到现在,仍然有大量的系统使用这种方式开发。然而这种开发方法存在着比较 严重的问题,对于开发稍微大一些的系统,容易潜藏很多问题。核心的问题在于,数据库管理系统使用的是“关系模型”,这种模型非常适合存储数据,但并不适合 表达“业务逻辑”,因为它不是为表达通用逻辑设计的。
我们在开发信息系统中使用的语言,例如C#、Java、PHP等等都是流行的通用语言,他们都非常适合表达复杂的业务逻辑。他们使用的都是“对象模型”。学习过一点任何面向对象语言的读者都很熟悉如何表达一个对象。
例如,表达一个人的概念,用C#语言是这样的:
class person
{
public string Name { get ; set ; }
public int Weight { get ; set ; }
public float Height { get ; set ; }
}
和我们刚才看到的,在数据库中,描述一个人的多元组模式,似乎差不太多。但是当两个对象之间有联系时,二者的区别就大了。
例如,在一个学籍管理系统中,一个学生需要选修若干门课程。为了表达“学生”和“课程”挣两个实体概念,以及二者之间的关系。在关系模型,也就是数据库中,是这样描述的:
(张三, 男,65kg, 1.75m)
(李四, 女,60kg, 1.65m)
(王五, 女,55kg, 1.55m)
(赵六, 男,75kg, 1.85m)
(数据结构,4学分,王可教授)
(C++入门,3学生,周翔教授)
(数字逻辑,2学分,俞山教授)
(张三,数据结构)
(李四,数据结构)
(张三,数字逻辑)
(张三,C++入门)
(李四,数字逻辑)
(王五,C++入门)
可以看到,一共使用了三张“表格”,第一个表格记录了学生的集合,第二个表格记录了课程的集合,第三个表格记录了“选课”的集合。可以看到,一个学 生可以选修多门课程,例如张三选修课了3门课程,李四选修了两门课程,同时以门课程也可以有多个人选修,例如上面显示的三门课程分别由两个人选修。这种关 系在称为“多对多”关系。对应的,另一种常见的关系是“一对多”关系,例如学生“分班”,通常是一对多关系,一个学生只能属于一个班级,一个班级有多名学 生。
而上面这个例子,如果在C#或Java这样的语言中,使用对象模型,又该如何描述呢?
class Course
{
public string Title { get ; set ; }
public string Credits { get ; set ; }
public string Teacher { get ; set ; }
public Student[] Students { get ; set ; }
}
class Student
{
public string Name { get ; set ; }
public string Sex { get ; set ; }
public float Weight { get ; set ; }
public float Height { get ; set ; }
public Course[] Courses { get ; set ; }
}
可以看到,定义了两个类,在“课程”这个类中,有一个“学生”字段,用一个数组记录了选修改课程的若干学生,同理,在“学生”类中,有一个“课程”字段,用一个数组字段,记录了这个学生选修的若干课程。
而在访问数据时,二者的差异就更大了:
如果使用数据库的关系模型,也就是使用 SQL 语言,查询选修了”数据结构”课程的学生姓名,需要使用连接语句:
SELECT Student.Name
FROM Student
JOIN StudentCourse ON Student.Name = StudentCourse.StudentName
JOIN Course ON Course.Title = StudentCourse.CourseTitle
WHERE Course.Title =‘数据结构’
上面的SQL语句中,把三个表连接起来,然后进行筛选,可以看到语句写起来还是相当麻烦的,而且这是一个最简单的结构,在实际系统中,情况还会复杂很多。
而如果使用对象模型,读取某一个学生选修的课程,简单地通过“点”语法就可以了:
例如 ZhangSan 是一个学生对象,那么 ZhangSan.Course[0].Teacher 就可以读取他选修的第1门课程的教师姓名了,这样和上面的SQL语句相比,就方便太多了。然而在开发系统的时候,二者都是必不可少的,因为就目前而言,数 据库还离不开关系模型,因此在访问数据库时,我们就必须使用SQL语句。
ORM
为了解决数据库使用的关系模型和编程语言使用的对象模型之间的差异,“ORM”应运而生。使用ORM,可以尽可能地隐藏关系模型的复杂性,使开发人 员能够方便地使用对象模型完成对数据库的操作。简单地时说,就是要尽可能地避免直接写SQL语句来实现各种对数据库的操作。也就是把使用C#、Java这 样的通用编程语言编写的语句,映射,或者更直接地说叫做翻译,为相应的SQL语句。
例如,一段用C#语言写的代码如下:
var custQuery = db.Customers.Where(c => c.City == "London" );
这段代码中,在数据库的客户表中查找所有城市为London的客户。如果使用 Linq To SQL 这个ORM,将会自动生成下面的SQL语句:
SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Phone],
[t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Fax]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[City] = @p0
– @p0: Input String (Size = 6; Prec = 0; Scale = 0) [London]
– Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20810.0
这仅仅是对一个表的查询,非常简单,所以效果还不明显。如果是一些更复杂的查询,就可以看出使用ORM的优势,它可以大大提高开发的效率。另外,借 助 Linq 这样的语言工具,编程的时候,便一起就可以进行类型检查,而不是像使用SQL那样,没有类型检查,只有到了运行时吃才能发现错误。这都将大大提高开发人员 的生产效率。
ORM 也不是万能的
当然,天下也没有十全十美的东西。ORM 也不例外,使用 ORM 确实可以大大提高开发效率,节省时间。但是毕竟这些映射(翻译)是由程序来完成的,在有的情况下,并不能保证生成的SQL语句是性能最优的。
因此,如果开发人员懂得SQL语句,就可以在开发过程随时监控程序的性能,如果出现问题,查找相应的SQL,分析问题产生的原因,这样就会好很多。
当然,也应该避免另一个倾向,过于怀疑 ORM 产生的SQL的质量。实际上,流行的ORM都是经过长期考验的,在绝大多数情况下,性能是有保证的。此外,尽管对于一个特定的情况,人脑可能可以构想出最 佳的SQL语句,但是在实际开发的时候,如果全部用手工写SQL,往往写出来并非的最优的SQL,还不如使用ORM产生的SQL。
因此,在开发中,使用ORM还是利远远大于弊的。同时随时注意性能和生成的SQL语句,这样既保证了高效的开发,又保证了代码的质量。
总结
最后,说说实际的ORM框架。在Java平台上,最流行的是Hibernate,推出已经很多年,最新版本是3,可以说是久经考验。在 .Net 平台,微软没有官方的ORM之前,最流行的是从Hibernate移植到.Net的Nhibernate,后来微软推出了自己的ORM,第一个是Linq To SQL,带有试验性质,现在已经停止升级,目前大力投入主推的是Entity Framework。
在我们的书中,我将比较详细地介绍 Entity Framework。在书中,我觉得应该先介绍 Entity Framework,然后在讲解 ASP.NET MVC,这样会条理更清晰。但是如果这样写的话,又担心会有读者会心急,买的是一本 Web 开发的书,看了半天访问数据库的东西,见不到Web程序,会很不开心。所以我在考虑如何找到一个合适的,折中的编写顺序,既能够保证读者学着开心,又能够 符合学习的规律。
我之所以有上面的担心,是因为很多读者确实看了开头的一两章,没有看到他要的东西,就开始着急。比如原来写的CSS的书,为了说明一些基础的东西, 在前面的章节用了一些表格的HTML标记,读者就发评论,说这本书是骗人的,书名号称讲CSS布局的书,其实用的都是表格布局。我们也很无奈,耐心看到后 面,自然会明白为什么写,但是现在很多读者都一方面希望能把内容讲清楚,另一方面又希望书里代码和案例都能够拿起来就用。所以这也给写书的人,提出了更高 的要求,尽可能地通过好的编排,实现读者的希望的效果。总之我们也将会更尽力地组织好,争取写出一本好书。

浙公网安备 33010602011771号