分享

Net PetShop3.0的数据访问技术及其改进

 天落雨 2006-01-20
使用ASP.NET开发网站,比起以前的ASP来,在界面设计和事件处理上有了很大改进。另外引入了(code behind)简化了页面文件中的代码,使我们能摆脱以前ASP页面中界面与VB Script交织的困惑。再通过把公用代码封装在用户控件(UserControl),在需要引用页面代码中加入Register 来引用控件即可,这有些像Java的Tag技术。

  但是如果要实现企业应用,只应用界面的改进技术是远远不够的,更重要的是要实现数据库访问和传递方面的改进。为了示范Ado.Net的数据库编程模式,并且在性能上的不输于Java的J2EE,迅速提供了.Net版本的PetShop。虽然关于这两种技术实现PetShop的优劣争论不断,在这里试图分析PetShop数据访问技术的优点和不足,并提出改进的方法。

  首先从 http://www./team/compare/ 下载最新的PetShop 3.0并安装后,其系统结构目录如下:

  其目录按逻辑很清晰的分为业务逻辑层(BLL),数据访问层(DAL),实体层(MODEL),为了能同时访问Oracle和SqlServer,通过DALFactory根据配置文件来创建不同数据库的DAL对象来实现,而执行数据库Sql操作都放在一个Helper类中,如访问Oracle的用的就是OraHelper,它封装了所有对数据库的底层操作。下面是示例代码段:

  public static int ExecuteNonQuery(OracleConnection conn, CommandType cmdType, string cmdText, params OracleParameter[] cmdParms)

  {

  OracleCommand cmd = new OracleCommand();

  PrepareCommand(cmd, conn, null, cmdType, cmdText, cmdParms);

  int val = cmd.ExecuteNonQuery();

  cmd.Parameters.Clear();

  return val;

  }

  我们看到了PetShop的数据访问方式,把所有数据读取,修改,新增的操作都用执行SQL语句来实现,并直接返回一个DataReader,接着DataReader是这样被填充到一个对象数组中:

  public IList GetItemsByProduct(string productId)

  {

  // Declare array to return

  IList itemsByProduct = new ArrayList();

  // Create a database parameter

  OracleParameter parm = new OracleParameter(PARM_PRODUCT_ID,OracleType.Char, 10);

  //Set the parameter value

  parm.Value = productId;

  //Execute the query

  using (OracleDataReader rdr = OraHelper.ExecuteReader(OraHelper.CONN_STRING_NON_DTC, CommandType.Text, SQL_SELECT_ITEMS_BY_PRODUCT, parm)) {

  // Scroll through the results

  while (rdr.Read()){

  ItemInfo item = new ItemInfo(rdr.GetString(0).Trim(), rdr.GetString(1),   rdr.GetDecimal(2), rdr.GetString(3), null);

  //Add each item to the arraylist

  itemsByProduct.Add(item);

  }

  }

  return itemsByProduct;

  }

  这个方法通过OraHelper查询到数据,然后用ItemInfo item = new   ItemInfo(rdr.GetString(0).Trim(), rdr.GetString(1), rdr.GetDecimal(2),   rdr.GetString(3), null);填充完数据的具体对象,就此.Net PetShop完成了数据的O/R映射,并返回了填充完对象的ArrayList。

  从以上.Net PetShop的数据访问实现方式来看有以下特点:

  实现了多种数据库访问,并隔离了数据访问的具体实现方式

  数据访问层和业务逻辑层的严格区分

  用DataReader填充具体对象,而不是传递DataSet,节省了服务器资源;

  但是这种方式也有它的不足之处:

  在代码中出现大量的新增,删除和更新Sql语句,没有用一个类来实现这些通用的操作;

  有大量参数赋值语句,可读性差,不利于代码的后期的维护;

  从DataReader填充到对象属性需要重复写代码;

  针对这些问题,通过应用Attribute和类反射机制,新增,删除和更新功能不需要再写Sql语句,参数赋值也不需要逐一写赋值过程,大大提高了编写数据访问代码的效率。

  下面详细介绍其实现方式:

  首先我们定义了以下Attribute,其主要代码如下:

  public class DataDynamic : Attribute

  {

  public DataDynamic(string fieldName,bool isKey)

  {

  _fieldName = fieldName;

  _isKey = isKey;

  }

  /// <summary>

  /// The name of the field in the database

  /// </summary>

  …

  }

  private string _fieldName = "";

  private bool _isKey = false;

  private string _oldValue = "null";

  }

  在这个自定义属性中,描述了在数据库中的字段信息:fieldName(字段名),isKey(是否主键),oldValue(修改前的值);

  然后在定义实体对象时需要定义其属性如下:

  public class NewsObject

  {

  private string id = "NewId";

  private string subject = "";

  /// <summary>

  /// The Id in the database

  /// </summary>

  [DataDynamic("id",true)]

  public string Id

  {

  get

  {

  return id;

  }

  set

  {

  id = value;

  }

  }

  /// <summary>

  /// The name in the database

  /// </summary>

  [DataDynamic("subject",false)]

  public string Subject

  {

  get

  {

  return subject;

  }

  set

  {

  subject = value;

  }

  }

  }

  在这里定义id为表主键,在BaseDataProvider数据访问组件中就是依靠这些信息自动产生更新和删除的Sql语句,而不再需要为每个对象个别定义Sql语句。访问该数据对象的代码变为:

  BaseDataProvider dataProvider = new BaseDataProvider(null," NewsObject");

  在BaseDataProvider中会获取数据并自动填充到NewsObject中,而删除一个对象则变为dataProvider.Delete(i),调用这个方法将自动删除相应的NewsObject,并产生删除数据库相应记录的Sql语句:delete NewsObject where id = 3。如果对某个NewsObject的信息做了修改,也只需调用dataProvider.Update(),就会产生相应的update语句,把数据自动更新到数据库。

  可见,通过这样的改进,能减少重复代码的编写,提高系统实现效率。但是也要付出一定的性能代价,因为运用类反射会消耗一定的系统资源。究竟孰优孰劣,还是个人权衡吧。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多