NHibernate in Action(第一章1.2)

1.2 .NET中的持久化方法

 
     我们已经讨论过如何在一些较大的系统中使用持久层来处理加载和保存数据。现在也有很多方法可以用于实现持久层,每个方法都有各自的优点和缺点。下面是一些流行的方法:
  • 手工编写代码
  • DataSets
  • LINQ-to-SQL
  • NHibernate(或其它类似的)
  • ADO.NET  Entity Framework
     尽管我们强烈推荐使用NHibernate,但是也可以考虑其它的这些选择。虽然我们知道,使用NHibernate来建立一个系统是非常简单的,但是并不意味着对每个系统来说它都是完美的。在接下来的部分中,我们将详细的测试和对比这几种方法,讨论与数据库访问和用户接口的关联。

1.2.1 选择持久层
 
     在应用程序中,你经常会加载、处理和保存数据库的元素。不管你使用的是什么持久层,在某些时候还是必须创建ADO.NET对象和执行SQL语句的。如果你每次处理出具的时候都要手动去写SQL将会是一件非常繁琐的事情,因此你可以将这些底层次的工作交给持久层去做。
     持久层是一套的用于使你保存和数据更简单的类库和公共组件。持久层通过ADO.NET执行SQL语句来实现,但是最复杂的过程是要求将这些语句封装在组件里面,并且能够理解如何持久化这些实体。这些组件还隐藏的具体的数据库,量减少与数据库的关联使得你的应用程序更易维护。例如,当你的SQL标识中包含了空白符或者保留字时,你必须为这些标志添加分隔符。比如SQL数据库泽添加括号,MySQL则使用back-ticks(不知道咋翻译)。有必要将这些详细信息隐藏起来并让持久层选择正确的分隔符。
     根据你选择的持久层实现方式,它们的内部关系有很大的区别。
     手写持久层
     自己编写持久层将包含许多工作。首先通常会建立一套通用的功能来处理数据库连接,执行SQL语句等等。接着在底层的最顶端,需要建立另外一套功能来保存,加载和查找你的业务实体。如果你需要引入缓存,业务规定约束或者处理实体之间的关系的时候,事情就变得更加复杂。
     手工编写使你的持久层有更大灵活性和可控性;你具有自由的设计的权限和能够简单的开发特定的数据库功能。但是这些仍然需要大量的工作且是非常繁琐的事情,即使你使用代码生成。
     基于DataSet的持久层
       Visual Studio可以使你很高效的生成你的持久层,通过几次点击就可以扩展你的新功能。Visual Studio生成的类知道如何访问数据库已经如何通过DataSet来加载和保存实体。
      另外,只需一点工作就可以开始了。但是你如果你需要控制其他东西就必须手写代码了,这是经常发生的(在1.3节将会介绍)。
     NHibernate持久层
      NHibernate提供一个快速建立持久层代码的所有功能。它可以加载和保存整个对象管理同时维护它们之间的关系。
     例如一个拍卖应用(例如eBay),NHibernate可以通过一个像下面这样的接口函数轻易的保存一个Item和Bids:
     public void Save(Item item) {
         OpenNHibernateSession();
         session.Save(item);
         CloseNHibernateSession();
     }
     在这里,Session是NHibernate提供的 一个对象。不用担心看不懂代码,现在我们只是想让你了解一下NHibernate如何简单的实现持久层。我们将在第二章开始讲NHibernate,你就会发现它是直接执行持久化操作的。你只要做的就是编写实体类和接受NHibernate如何去持久化这些实体。在深入探讨NHibernate之前,我们先来简单的看一下微软最新介绍的持久化技术。
     基于Linq-to-SQL的持久层
     语言基础查询(LINQ)是由微软2007年开发的。他能够实现查询和以及集合的操作,像C#和VB这样的.net语言提供了一组扩展,使得这些操作就像数据库提供的SQL语言一样。LINQ的目标是想让查询变成变成编程语言的一部分。LINQ to SQL通过LINQ的扩展提供语言级的数据访问。它是基于ADO.NET来实现表,行与类和对象直接的映射关系。
     LINQ to SQL使用.NET的用户自定属性和xml文件来表示映射信息。这些信息用于自动处理关系数据库中的持久化对象。一个表格映射到一个类,表格中的列可以映射到类的属性,表格直接的关系也可以通过属性来表示。LINQ to SQL通过动态SQL语句或者存储过程自动追踪对象和数据库的修改及更新。通常的当你使用了LIING to SQL,那么大多数时候是不需要写SQL语句的。
     和NHibernate比起来LINQ to SQL有一些主要的局限性。例如,它是映射是类与表格直接严格一一对应的,它不可以实现基于类属性和表格列之间的映射。虽然你可以创建一个自定义的LINQ 数据库类型,但是linq to sql 主要还是针对SQL数据库的解决方案。
     ADO.NET ENTITY FRAMEWORK
     ADO.NET ENTITY FRAMEWORK是微软在.NET 3.5 SP1中提出的一个新的持久化方案。从一个高层次来说,他依靠微软的全力的商业支持和背景,计划提供一个与NHibernate类似的持久层。这个承诺对于那些需要供应商支持解决方案的开发者来说是个非常吸引的选择。但是在编写此书的时候,Entity Framework还是早期的beta版本而且还有很多功能集合未完成。
     ADO.NET ENTITY FRAMEWORK 1.0版本提供了对多种数据库的支持以及更复杂的映射。但是它不会真正的支持“对象第一”的开发,最早也要到2009年的第二版才会支持通过mapping来生成数据库表。对于那些要求严格的ORM,NHibernate还是
有明显的优势。
 
1.2.2 实体的实现
     一旦你选择一个持久层的解决方案,那么你就得开始建立程序需要操作的业务对象或者实体。这些类表示的是程序需要操作的现实中的元素。对于拍卖程序程序来说,User,Item和Bid是一个简单的例子,我们接下来会讨论如何实现上述三种方式的业务实体。
     手工编码的实体
     回过来看拍卖系统这个例子,假设需要的实体有:User,Item和Bid。除了他们包含的数据之外,你还希望他们之间有一些关系。例如,一个Item包含了一个Bid集合,一个Bid有与一个Item管理。在C#的类中,他可以用item.Bids这样一个集合表示,用biid.Item这样的属性表示。面向对象的视图不同于关系视图,它没有主外键,只有关联关系。面向对象同时也提供了一些强大的模型概念,比如继承和多台。
     手工编写的实体不受其它任何约束,它们甚至可以定义实体在数据库持久化的方式。他们可以独立的使用和供其它系统共享使用,这对于复杂的环境是非常重要的好处。
     但是他们编码起来非常繁琐和困难。考虑到我们必须使用手工编写继承于其它实体的持久层实体,通常会使用代码生成或者一些基类(例如DataSet)来尽量减少添加功能的工作量。这些功能可能关系到一些持久层,交互或者信息的表现。所以如果没有一个有用的框架,这些功能将会花费很多时间来实现。
     DataSet中的实体
     一个DataSet表示了一个集合的数据库表,对应的,这些表格也包含了相应的实体。DataSet存储业务对象的方式很像数据库。你可以很容易使用自动生成类型的DataSet来修改数据,通用它也可以用于插入业务逻辑和规定。
     .NET和IDE提供了许多维护DataSet数据的功能。但当你考虑以面向对象设计的的方法来考虑业务对象时,DataSet(无论是否有类型的)就能难满足要求。毕竟,业务对象必须表现现实的元素,这些元素要有数据和动作。他们可能会被一些想继承这样的高级关系连接起来,但是DataSets无法实现这些。这个层次上的实体设计自由只能通过手动编写才能实现。
     NHibernate中的实体
     NHibernate是非强加性的。你可以使用它来手动编写(或生成)实体。你必须提供表明这些实体如何加载和保存的映射信息。做完这些后,NHibernate就可以开始负责保存或从数据库中取出你的面向对象实体。
     对象与关系数据之间有几个主要的不同点。如果试图将这两者一起使用的话将会产生范式失配(也叫做对象关系阻抗失配impedance mismatch).我们在1.3节将探讨这种适配。在本章的结尾,你将会对导致范式匹配的原因及NHibernate如何解决这个问题有一个清晰的概念。
     ENTITIES与LINQ to SQL
     LINQ to SQL跟NHibernate的ORM实现方式很相像。LINQ to SQL使用POCO对象来表示你应用程序的数据(实体)。对象和数据库表中的映射是通过代码中的属性和xml文本来表示。映射和实体类编写完成之后,LINQ to SQL框架会生成数据库操作的语句。
     一旦实体类被引入,你必须考虑如何呈现给用户端。
 
1.2.3  在用户界面显示实体
     
    使用NHibernate意味着要使用实体类,而使用实体类则影响UI的实现方式。对于客户端来说,UI是非常重要的元素。无论是web应用程序(使用ASP.NET)还是Windows应用程序,都需要满足用户的需求。虽然深入讨论UI如何实现并不是该书的一部分,但是持久层的实现方式却直接影响的UI的实现。
     在本书中,我们把UI当做表示层:.NET提供了显示信息的控制方法。这些简单的操作都依赖于信息的存储方式。
     我们不期望.NET实体的绑定方式会很快改变。虽然微软已经开始积极推动用户在.NET应用程序中使用实体类,像公司一直在推广ADO.NET Entity Framework 和LINQ to SQL。出于这个原因,我们这一节中不会讨论相关的技术。
     基于DATASET的表示层
     微软已经为大部分.NET控件添加了对DataSet数据绑定的支持。它能够很容易的将DataSet绑定到控件上,以便于显示信息和DataSet的变化(用户触发)做出响应。
     使用DataSet可能是最高效的实现表现层。你可能会对数据如何显示失去一些控制,但是它能够满足大多数情况。这种情况下手工编写实体将会更加复杂。
     表示层与实体类
     NHibernate数据绑定的手工编码实体类通常是件困难的事情。因为实体类经常表现为各种形式。DataSet通常是由表格、列和行组成的,但是手写实体类---你自己设计的类---包含了字段和方法不包含标准化得访问和显示方式。.NET运行我们将对象的公共属性绑定到控件上。这对一些简单的问题已经足够了。如果你想要更加灵活,你就必须手写一些代码来获取实体数据到UI中并保存回数据库。
     手写实体与UI绑定还是相当的简单。但是,如果你觉得这样还很麻烦,那么你可以尝试使用一些开源的项目来解决这个问题。、ObjectViews就是其中一个。
     同样,当你处理一些边缘问题,比如一些复杂的报表的时候,不要忘记你还是可以使用回DataSet的,DataSet在这方面维护起来更加简单。事实上,在编码过程中,很少有报表工具能够很好的支持实体绑定,所以DataSet可以说是你的最佳选择。我们会在第九章讨论这个问题。
     使用持久化信息将会影响UI的设计方式。数据必须在UI打开的时候加载并且在它关闭的时候保存。NHibernate提供了一些用于处理该过程的建立,你可以在第八章看到。
 
1.2.4 实现CRUD操作
 
    当你使用持久化信息时候,你就必须关注如何持久化和检索信息。创建,读取,更新,删除(CRUD)操作是最原始的操作即使是最简单的应用。大多数时候这些操作都是由表示层触发的。例如,用户可能点击一个按钮来显示一个元素。持久层将会去加载这个元素,并将它绑定到表单并显示出来。
     无论你似乎用的是什么方式,这些原始的操作都很好理解也很好实现。一些复杂的的操作会在下一部分讲。
 
     手写代码的CRUD操作
     手写的CRUD操作可以确切的执行你想要的东西,因为执行了自己编写的SQL语句---但是这仍然是非常繁琐的工作。所以有必要引进一个框架来生成这些SQL语句。一旦你知道加载一个实体就是从数据库中执行一个SELECT语句,你就可以自动生成这些原始的CRUD操作。但是对于一些复杂的查询和关联实体,你就必须编写更多代码来实现。
     DataSet的CRUD操作
     你知道大多数持久层都可以使用DataSet来生成。这写持久层包含了一些执行CRUD操作的类。同时VS 2005和.NET2.0也提供了更加强大的类:TableAdapters。
     这些类不仅支持这些原始的CRUD操作,而且他们还是可扩展的。你不仅可以添加函数来调用存储过程或者点击几下就可以生成SQL语句。但是如果你想实现一些复杂功能,你就必须进行编码。下一节你就会看到有些有用的功能并不是那么容易实现的,而且DataSet这样的结构可能使得实施变得更复杂。
     NHinernate的CRUD操作
       一旦你写好了NHibernate的实体映射信息,你就可以通过调用一个函数来实现CRUD操作。这是ORM工具的一个基本功能。如果你提供了它所需要的所有信息,那么它就可以解决每个操作引起对象关系失配。
     NHibernate能够搞笑的执行CRUD操作。经验和不断的测试可以帮助你发现很多优化途径和最近实践。例如,当你在处理实体的时候,你可以通过延迟加载用户提交的事务来达到最佳实践。这个时候,你就只需使用一个连接就可以保存所有的实体。
     LINQ to SQL的CRUD操作
     从表面上看,LINQ to SQL 的CURD操作跟NHibernate非常类似---你可以通过一个简单的函数调用来加载,保存,更新和删除对象。LINQ to SQL的实体提供较少的的CURD的细节操作,可能是好事也可能是坏事,这依赖于你项目的复杂程度。
     现在我们已经降到了大部分的持久化步骤和操作,同时我们也探索了NHibernate的一些高级功能。
posted @ 2010-02-10 12:16  Chris Cheung  阅读(827)  评论(0编辑  收藏  举报