日期:2009-12-02  浏览次数:20463 次

.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 page
  int 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 in
  while (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 array
  if (index == pageSize)
  return results;
  else {
  // not a full page, redim array
  ProductResults[] 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 props
  public 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在连接数据库之后马上进行填充,然后迅速释放掉数据库连接的方式更加有利于大量用户的并发访问。
   <