我在前面几篇介绍过我的Winform开发框架的相关内容,其中主要集中在界面展现以及各层的总体设计上,还没有空来得及深入进行各个重要细节的讲解,今天我们来介绍、讨论下我的Winform开发框架之数据访问层的设计方面的知识,希望对大家有所帮助。
前面介绍过,该Winform开发框架支持多种数据库的访问,只需要对配置进行修改即可切换,如下图所示。
其中我们可以看到,里面有几种数据访问层的相关数据,大致知道是通过同一的IDAL数据访问层接口派生出几个对应不同数据库的操作层,由业务逻辑层BLL进行相应的调用,但是具体细节从上图并不能了解到。
其实他们的大致关系如下图所示。
首先BLL层,通过BLLFactory对象,根据配置信息,实例化不同的业务访问对象,转换为数据访问层接口进行调用的,BLLFactory通过反射间接方式,构建出不同数据库对象的数据访问层,而数据访问对象,他们都集成了基类BaseDAL,这个基类封装类了绝大多数的增删改查等基础性操作,并通过高度抽象,只需要继承该基类的子类重载部分函数即可完成较为丰富的操作实现。具体的继承关系如下图所示。
由于每个不同数据库都需要拥有一个BaseDAL,那么很多相同的操作代码就会发生冗余,因为大多数数据库的基础操作是一样的,只有一部分比较特别,需要进行个性化处理,因此对以上的数据访问层进行优化设计,得到下面的设计图,如下所示。
由于把BaseDAL层的通用操作,进一步提升抽象到AbstractBaseDAL 类里面进行管理,因此,BaseDAL虽然在各种数据库的数据访问层中存在,但是,却只是需要实现很少的代码,如下所示。
因为不同的数据库,FindFirst(查找第一条)、FindLast(查找最后一条)、Insert2(插入记录后,返回新增的主键值)、以及分页查询FindToDataTable、FindWithPager等不同。因此数据访问层的BaseDAL子类需要覆盖基类AbstractBaseDAL的这些实现。
通过实现部分个性化数据库操作的函数及强大的基类
AbstractBaseDAL实现,我们可以看到,整个数据访问层基类得到非常强大的操作功能,如下所示。为了说明问题,我列举几个上面函数不同的实现给读者,以便说明问题。
1)SqlServer的FindFirst语句如下:
2)Oracle的FindFirst语句如下:
string sql = string.Format(@"Select * from (Select {0} From {1} Order by {2} ASC) WHERE ROWNUM <= 1 ORDER BY ROWNUM ASC", selectedFields, tableName, GetSafeFileName(sortField));
3)Sqlite的FindFirst语句如下:
string sql = string.Format("Select {0} From {1} Order by {2} ASC LIMIT 1", selectedFields, tableName, GetSafeFileName(sortField));
为了实现功能强大的数据访问基类,并尽可能减少重复代码,高度提炼基类是很有效的方法。适当的集成关系,使得代码量更少,扩展更加容易,这个就是我的Winform框架的优化思想。