我,海东

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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

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

 

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

 

首先从http://www.gotdotnet.com/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语句,把数据自动更新到数据库。

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

 

posted on 2005-09-14 10:41  iseast  阅读(2790)  评论(5编辑  收藏  举报