对比.NET PetShop和Duwamish来探讨Ado.NET的数据库编程模式

ado|编程|数据|数据库

  对比.NET PetShop和Duwamish来探讨Ado.NET的数据库编程模式


概述Ado.NET为我们提供了强大的数据库开发能力,它内置的多个对象为我们的数据库编程提供了不同的选择。但是在允许我们灵活选用的同时,许多初学者也很迷惑,我到底是应该使用DataReader还是应该使用DataAdapter?我只想读取一小部分数据,难道我一定要Fill满整个DataSet吗?为什么DataReader不能和RecordSet一样提供一个数据更新的方法?DataSet到底有什么好处?在本文中,我将对.NET PetShop的数据库编程模式和Duwamish的数据库编程模式进行一些简单的分析和对比。如果您也有以上疑问的话,相信在读完本文之后,就可以根据具体的需要来制定一个最适合您应用的数据库编程模式。

目录
  • .NET PetShop和Duwamish简单介绍
  • 结构简述
  • Duwamish数据访问剖析
  • .NET PetShop数据访问剖析
  • 分析总结

.NET PetShop和Duwamish简单介绍相信大家一定听说过有名的"宠物店大战",没错,本文的主角之一就是获胜方.NET PetShop,微软号称以27倍的速度和1/4的代码量遥遥领先于基于J2EE的PetStore宠物商店。虽然SUN也曾对此抱怨过不满,指责此"大战"有水分,不过无论如何,.NET PetShop绝对是一个经典的.NET实例教程,至少为我们提供了一条赶超J2EE的“捷径” :),它的下载地址是:http://www.gotdotnet.com/team/compare
.NET PetShop宠物网上商店首页而Duwamish则是一个外表简单,内部却极其复杂的一个网上书店的.NET完整应用范例,作为一个微软官方的Sample,它同时提供了C#和VB.NET两种语言版本,并且还附上了大量详尽的中文资料,如果打印出来,实在是居家旅行,临睡入厕必备之物。什么?您没听说过?呵呵,如果您装了Visual Studio .NET的话,它就在您的硬盘上静静的躺着呢,不过还没有被安装,您可以在您的VS.NET 的Enterprise Samples目录下找到并安装它,例如:C:\Program Files\Microsoft Visual Studio .NET\Enterprise Samples\Duwamish 7.0 CS。
Duwamish网上电子书店首页

结构简述两家商店都采用了n层应用结构(毫无疑问,n层结构的应用架构应该绝对是您开发.NET应用的首选,哪怕您只想做一个网页计数器),不同的是,PetShop采用的是最常见的三层应用结构,分别为表示层,中间层和数据层。而Duwamish则采用的是一个四层应用结构,并使用不同的项目分隔开,分别为表示层,业务外观层,业务规则层和数据层。至于这两种结构分别有什么优点和缺点,以及为什么要这么分层,我们不进行详细讨论,因为本文的重点不在于此。我们主要分析的是他们的数据库编程的模式。

Duwamish数据访问剖析首先,我们来看看Duwamish书店,它采用的是DataAdapter和DataSet配合的数据存储模式,所不同的是,它对DataSet进行子类化扩展作为数据载体,也就是采用定制的DataSet来进行层间的数据传输,下面是一个定制的DataSet示例:
public class BookData : DataSet{  public BookData()  {       //       // Create the tables in the dataset       //       BuildDataTables();  }  private void BuildDataTables()  {        //        // Create the Books table        //        DataTable table   = new DataTable(BOOKS_TABLE);        DataColumnCollection columns = table.Columns;                columns.Add(PKID_FIELD, typeof(System.Int32));        columns.Add(TYPE_ID_FIELD, typeof(System.Int32));        columns.Add(PUBLISHER_ID_FIELD, typeof(System.Int32));        columns.Add(PUBLICATION_YEAR_FIELD, typeof(System.Int16));        columns.Add(ISBN_FIELD, typeof(System.String));        columns.Add(IMAGE_FILE_SPEC_FIELD, typeof(System.String));        columns.Add(TITLE_FIELD, typeof(System.String));        columns.Add(DESCRIPTION_FIELD, typeof(System.String));        columns.Add(UNIT_PRICE_FIELD, typeof(System.Decimal));        columns.Add(UNIT_COST_FIELD, typeof(System.Decimal));        columns.Add(ITEM_TYPE_FIELD, typeof(System.String));        columns.Add(PUBLISHER_NAME_FIELD, typeof(System.String));        this.Tables.Add(table);  }………}

我们可以看到它有一个BuildDataTables方法,并且在构造函数中调用,这样,定制的Books表就和这个DataSet捆绑在一起了,省得以后还要进行Column Mapping,这真是个好主意,我怎么就没有想到呢? :)解决了数据结构,接下来看看数据层的代码实现,在Duwamish中,数据层中有5个类,分别是Books,Categories,Customers和Orders,每个类分别只负责有关数据的存取。下面是其中一个类的示例代码:

private SqlDataAdapter dsCommand;public BookData GetBookById(int bookId){    return FillBookData("GetBookById", "@BookId", bookId.ToString());}private BookData FillBookData(String commandText, String paramName, String paramValue){    if (dsCommand == null )    {        throw new System.ObjectDisposedException( GetType().FullName );    }                BookData   data    = new BookData();    SqlCommand command = dsCommand.SelectCommand;    command.CommandText = commandText;    command.CommandType = CommandType.StoredProcedure; // use stored proc for perf    SqlParameter param = new SqlParameter(paramName, SqlDbType.NVarChar, 255);    param.Value = paramValue;    command.Parameters.Add(param);                dsCommand.Fill(data);    return data;}

这里就是数据层的代码了,我们在这里可以看到Duwamish采用了DataAdapter来将数据填充到定制的DataSet中,然后返回该DataSet。我感到很奇怪的是在数据存取层中竟然可以看到GetBookById这样具体的数据存取方法,虽然最后还是有一个抽象出来的FillBookData方法,但是上面还有三层啊,底层都做到这份上了,那上层都做些什么呢?答案是数据检查,上层基本上都在做一些很严密的数据合法性校验(当然也会包括一些比较复杂的事务逻辑,但是并不多),示例代码如下:

public CustomerData GetCustomerByEmail(String emailAddress, String password){    //    // Check preconditions    //    ApplicationAssert.CheckCondition(emailAddress != String.Empty, "Email address is required",ApplicationAssert.LineNumber);    ApplicationAssert.CheckCondition(password != String.Empty, "Password is required", ApplicationAssert.LineNumber);    //    // Get the customer dataSet    //    CustomerData dataSet;    using (DataAccess.Customers customersDataAccess = new DataAccess.Customers())    {dataSet = customersDataAccess.LoadCustomerByEmail(emailAddress);    }    //        // Verify the customer's password    //    DataRowCollection rows = dataSet.Tables[CustomerData.CUSTOMERS_TABLE].Rows;    if ( ( rows.Count == 1 ) && rows[0][CustomerData.PASSWORD_FIELD].Equals(password) )    {        return dataSet;    }    else    {        return null;    }}

在这个方法中,真正进行数据存取的实际上只有

dataSet = customersDataAccess.LoadCustomerByEmail(emailAddress);

这么一句,是直接调用的数据层。其它都是在进行合法性校验,我们可以感悟到,进行一个真正的企业级开发需要考虑的系统健壮性有多么重要。


.NET PetShop数据访问剖析OK,Duwamish看完了,下面我们来看看PetShop的数据访问机制。PetShop只有一个项目,它采用的分层办法是将中间层和数据层都写成cs文件放在Components目录里,其中数据层就是一个名为Database的类,它封装了所有对数据库的底层操作。下面是示例代码段:
public void RunProc(string procName, out SqlDataReader dataReader) {SqlCommand cmd = CreateCommand(procName, null);dataReader = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);}

我们看到了一个跟Duwamish截然不同的另一种数据访问方式,它将所有的数据访问方法抽象出来做成一个RunProc方法,至于返回数据呢,呵呵,它有点偷懒,直接返回一个DataReader给你,你自己去读吧。还记得Duwamish采用的层间数据传输载体是什么吗?对了,是DataSet,它被数据层填充后返回给了中间层。但是这里,数据层和传输层的数据传输载体变成了DataReader,实际上,还不能称它为数据载体,因为数据还没开始读呢,在这里,DataReader的作用和指针有点类似,也许我们应该称它为“数据引用”:)接着往下看,DataReader被怎么“处理”的:

public ProductResults[] GetList(string catid, int currentPage, int pageSize, ref int numResults) {numResults = 0;int index=0;SqlDataReader reader = GetList(catid);ProductResults[] results = new ProductResults[pageSize];// now loop through the list and pull out items of the specified pageint start = (int)((currentPage - 1) * pageSize);if (start <= 0) start = 1;// skip for (int i = 0; i < start - 1; i++) {if (reader.Read()) numResults++;}if (start > 1) reader.Read();// read the data we are interested inwhile (reader.Read()) {if (index < pageSize) {results[index] = new ProductResults();results[index].productid = reader.GetString(0);results[index].name =  reader.GetString(1);index++;}numResults++;   }reader.Close();// see if need to redim arrayif (index == pageSize)return results;else {// not a full page, redim arrayProductResults[] results2 = new ProductResults[index];Array.Copy(results, results2, index);return results2;}}

注意到currentPage和pageSize了吗?原来在这里就进行了数据分页,只返回满足需要的最少的数据量,而不是象我们很多喜欢偷懒的人一样,简单的将整个DataTable一股脑的绑定到DataGrid,造成大量的数据冗余。在这里,数据被真正的读出来,并且被手动填充到一个自定义的对象数组中,我们来看看这个数组的定义:

public class ProductResults {private string m_productid;private string m_name;// product propspublic string productid {get { return m_productid; }set { m_productid = value; }  }public string name {get { return m_name; }set { m_name = value; }  }}

非常之简单,不过我有点奇怪为什么不使用struct呢?是不是.NET中struct和class的性能差距已经可以忽略不计了?


分析总结通过观察这两个商店的具体实现,我们得到了两个不同的数据访问模式,Duwamish采用的是以DataSet为核心,因为DataSet提供了这方面大量的相关方法,所以整个应用的数据传输,数据格式定义,数据校验都围绕着DataSet来进行,整个架构定义非常清晰和严谨,但是却显得有些庞大。PetShop在整个程序中没有采用一个DataSet,程序非常的简洁,轻灵,但是没有Duwamish那么强的健壮性。这两个程序是Microsoft公司不同的小组写出来的代码,所以有着不同风格。不过都应该能代表.NET的标准模式。看到这里,你应该对文章开头提出的那些疑问有一个比较形象的认识了吧。另外,请再次注意,PetShop在打开数据连接之后,并没有马上读取数据,而是将DataReader传递给另外的对象来执行数据读的操作,然后才关闭连接。这样,数据连接的时间加长了,而数据库连接是一项非常宝贵的服务器资源,相比之下,Dawamish在连接数据库之后马上进行填充,然后迅速释放掉数据库连接的方式更加有利于大量用户的并发访问。再一点,上文的程序中没有提到更新操作,PetShop采用的是使用Command对象执行单个存储过程的方式来进行更新操作,是属于一种在线即时数据更新模式。而Dawamish采用的是DataAdapter的Update方法,将DataSet的改变一次性的提交到数据库中,属于离线数据更新模式。这种模式的好处是可以一次性更新大批量数据,减少数据库的连接次数。缺点是如果数据库在改动非常频繁的情况下需要实时的跟踪数据变化就不合适了。需要根据具体的情况采用具体的数据更新办法。总的来说,如果您只需要快速的读取数据并显示出来,推荐您采用DataReader,如果您需要对数据进行大量的修改,还有大量并发访问的可能,而且不需要实时的跟踪数据库的变化,推荐您使用DataSet。当然,这两种情况有点极端了,实际的应用环境也许有着很复杂的条件,具体需要您自己审时度势,综合采用,不过我个人还是比较喜欢PetShop那种轻灵的风格 :)

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索数据库
, 数据
, dataset
, petshop
, 一个
Columns
,以便于您获取更多的相关知识。

时间: 2024-09-14 18:59:11

对比.NET PetShop和Duwamish来探讨Ado.NET的数据库编程模式的相关文章

多核时代:并行程序设计探讨(7)——并行编程模式概览

                                          并行编程模式概览 前面的5.6篇博文,都是和并行编程相关的基础知识,如果你一路看来,基本上也能够开始进行并行编程设计了,也可以和别人吹吹牛.聊聊天了. 但"欲穷千里目,更上一层楼",前面的毕竟都是基础知识,拿来直接设计,虽然能够完成任务,但就像在茫茫大海中航行,没有灯塔,难免会走很多弯路.甚至绝路! 所以我们要在这些基础知识之上,学习一套系统的分析问题.设计方案.应用实现的理论来指导我们作出正确的.优秀

漫谈.Net PetShop和Duwamish ADO.NET数据库编程

ado|编程|数据|数据库 概述 ADO.NET为我们提供了强大的数据库开发能力,它内置的多个对象为我们的数据库编程提供了不同的选择.但是在允许我们灵活选用的同时,许多初学者也很迷惑,我到底是应该使用DataReader还是应该使用DataAdapter?我只想读取一小部分数据,难道我一定要Fill满整个DataSet吗?为什么DataReader不能和RecordSet一样提供一个数据更新的方法?DataSet到底有什么好处? 在本文中,我将对.net PetShop的数据库编程模式和Duwa

Visual C++ ADO数据库编程入门(上)

ado|c++|visual|编程|数据|数据库   ADO 是目前在Windows环境中比较流行的客户端数据库编程技术.ADO是建立在OLE DB底层技术之上的高级编程接口,因而它兼具有强大的数据处理功能(处理各种不同类型的数据源.分布式的数据处理等等)和极其简单.易用的编程接口,因而得到了广泛的应用.而且按微软公司的意图,OLE DB和ADO将逐步取代 ODBC和DAO.现在介绍ADO各种应用的文章和书籍有很多,本文着重站在初学者的角度,简要探讨一下在VC++中使用ADO编程时的一些问题.我

怎样在PHP中通过ADO调用Access数据库和COM程序

access|ado|程序|数据|数据库 PHP4已经支持Microsoft的COM技术.然而文档中在COM部分却提得很少. 这儿是几个我试过的例子.希望这些给你一些概念.注意的是这些只能运行在32位的Microsoft Windows平台下. 用php激活ADO ADO是Microsoft的数据库对象技术.ADO里面包括连接数据库的对象,从查询语句中返回数据的记录集对象和表现数据元素的字段对象. 许多数据库不直接支持ADO.代之的是很多数据库支持低两级的Microsoft数据库技术:ODBC和

使用ADO封装类的数据库程序开发实例(上)

源代码运行效果图如下: 开发实例(上)-vc数据库编程实例ado"> 一.前言 用过ADO的人都知道, 调用ADO要处理很多"麻烦"的事情,如异常处理等,要写很多try - catch块. 有点不甚其烦.我干脆把常用的函数都封装起来,免去老是要写try - catch块的麻烦.做起来虽然没有什么技术含量,但也比较烦琐,所以只完成了一部分,且由于时间及个人水平有限,没有对封装的东西作全面测试,并必定有很多错误,但想到对某些朋友可能有用.所以先"捐"出来

PHP中通过ADO调用Access数据库

access|ado|数据|数据库 我看了那篇<怎样在PHP中通过ADO调用Asscess数据库和COM程序>文章后,马上作了测试,结果失败了.伤心是不是. 怎么办?我只好去PHP官方网站求助,皇天不负有心人,终于我找到了答案-- 具体的解决方法如下: (1)进入http://php.weblogs.com/adodb,下载相应的ZIP包:同MICROSOFT公司的ADO一样,该东东用PHP实现ADO同各种各样数据库打交道(太好了,所有类型的数据库都能处理). (2)解包,里面文件很多,不过有

PHP中通过ADO调用Asscess数据库

ado|数据|数据库 我看了那篇<怎样在PHP中通过ADO调用Asscess数据库和COM程序>文章后,马上作了测试,结果失败了.伤心是不是. 怎么办?我只好去PHP官方网站求助,皇天不负有心人,终于我找到了答案-- 具体的解决方法如下: (1)进入http://php.weblogs.com/adodb,下载相应的ZIP包:同MICROSOFT公司的ADO一样,该东东用PHP实现ADO同各种各样数据库打交道(太好了,所有类 型的数据库都能处理). (2)解包,里面文件很多,不过有用的只有oh

关于用 ADO 创建 Access 数据库

access|ado|创建|数据|数据库 要在网站上使用 Access 数据库,不必购买 Microsoft Access.可以在 Active Server Page 脚本中用 ODBC 数据资源管理器或 Data Link 程序或编程创建新的 Access 数据库.   ADO 本身没有创建新的 Access 数据库的方法.要在 Active Server Page 中创建一个新数据库,必须使用 ADOX.ADOX 包含在 MDAC 2.1 及其更新版本中,可从 Microsoft 下载(h

用ADO.NET管理数据库

ado|数据|数据库 使用ADO.NET管理数据库中的关系(relation)非常简单.作为返回单个行集合(rowset)到数据存储(data store)的代替,你可以返回多个行集合并在数据集(DataSet)中将它们关联起来.在ADO.NET中使用关联的数据表(DataTable)有很多好处,包括有将数据存储为层次结构的能力.更容易更新数据.有在列中使用表达式的能力等等. 本文介绍ADO.NET中基于列(column-based)的表达式和计算.我将演示数据列(DataColumn)上集合函