随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了。

其实也许我们每天面对的太多东西了,觉得很多都稀松平常了,即使很细微的地方,可能我们都已经形成习惯了。反过来,如果我们切换到其他领域,如IOS、android,那么开始我们可能对里面很多设计的规则不甚了解,开始可能也是一头雾水。

本篇继续上一篇《循序渐进开发WinForm项目(1) --数据库设计和项目框架的生成》,继续介绍如何循序渐进开发Winform项目,继续分析介绍Winform的项目代码,从而让我们更加了解其中的分层和项目框架的组成等内容。

1、数据访问接口的定义

上面我们分析了实体类的定义,本节继续分析其他部分的内容,如数据访问接口成的定义如下所示。

namespace WHC.TestProject.IDAL
{
/// <summary>
/// 客户信息
/// </summary>
public interface ICustomer : IBaseDAL<CustomerInfo>
{
}
}

这里面的代码很简单,没有多余的代码行,那么里面究竟发生了什么呢,其中的IBaseDAL又是什么定义呢?

其实,IBaseDAL就是定义了很多我们开发用到的基础接口,如标准的增删改查,以及衍生出来的一些其他接口,如分页查询,条件查询等接口内容。这个ICustomer就是用来定义一些除了标准接口不能实现外的业务接口。

IBaseDAL通过传入一个实体类,从而方便给基类接口提供强类型的数据类型指定,提高我们的开发效率,减少出错的机会。

我们可以在VS里面查看IBaseDAL的定义,如下所示:

可以看到里面很多相关的接口定义,有返回实体T的,也有返回List<T>的,还有DataTable类型等等,这些基础接口,经过我们多个项目的应用实践,已逐步稳定并能够提供很好的接口支持,方便我们快速调用处理。

即使我们在没有实现任何业务接口的情况下,仅仅利用标准的基类API,也基本上能够完成绝大多数的数据操作功能了。

2、数据访问接口实现类的定义

我们分析完IDAL的数据访问接口成的定义后,继续了解一下,如何基于这个接口进行访问层的实现设计的。数据访问的实现层在项目中的位置如下所示(以基于SqlServer的DALSQL层进行分析)。

它的类代码定义如下所示。

namespace WHC.TestProject.DALSQL
{
/// <summary>
/// 客户信息
/// </summary>
public class Customer : BaseDALSQL<CustomerInfo>, ICustomer
{

数据访问接口实现层和接口定义层一样,都有一个基类,如基于SqlServer实现的基类为BaseDALSQL,这个基于SqlServer的数据访问基类,它也是继承自一个超级基类(大多数的实现在这里)AbstractBaseDAL。他们之间的继承关系如下所示

而我们刚才在项目工程的图里面看到,BaseDALSQL、IBaseDAL、AbstractBaseDAL这些类库由于具有很大的通用性,为了减少在不同的项目中进行复制导致维护问题,因此我们全部把这些经常使用到的基类或者接口,抽取到一个独立的类库里面,为了和普通的DotNET公用类库命名进行区分(WHC.Framework.Commons),我们把它命名为WHC.Framework.ControlUtil。

BaseDALSQL基类的定义如下所示。

这样做的好处是,在所有的模块里面,避免复制导致的版本维护问题,同时也减少代码的重复生成,增量生成的全部代码,可以一次性复制到整个项目工程里面,而不会导致基础类库的替换,因为这些基类不在生成目录里面,所有生成的类文件,都是和业务表相关的,如下所示。

具体的数据访问实现类(如Customer),它把数据库信息转换为实体类,有一个函数,在代码生成的时候已经生成;同时在把实体类的属性保存到数据库也有一个类似CRM的映射关系,从而实现可空的字段获取和更新操作。

        /// <summary>
/// 将DataReader的属性值转化为实体类的属性值,返回实体类
/// </summary>
/// <param name="dr">有效的DataReader对象</param>
/// <returns>实体类对象</returns>
protected override CustomerInfo DataReaderToEntity(IDataReader dataReader)
{
CustomerInfo info = new CustomerInfo();
SmartDataReader reader = new SmartDataReader(dataReader); info.ID = reader.GetString("ID");
info.Name = reader.GetString("Name");
info.Age = reader.GetInt32("Age");
info.Creator = reader.GetString("Creator");
info.CreateTime = reader.GetDateTime("CreateTime"); return info;
} /// <summary>
/// 将实体对象的属性值转化为Hashtable对应的键值
/// </summary>
/// <param name="obj">有效的实体对象</param>
/// <returns>包含键值映射的Hashtable</returns>
protected override Hashtable GetHashByEntity(CustomerInfo obj)
{
CustomerInfo info = obj as CustomerInfo;
Hashtable hash = new Hashtable(); hash.Add("ID", info.ID);
hash.Add("Name", info.Name);
hash.Add("Age", info.Age);
hash.Add("Creator", info.Creator);
hash.Add("CreateTime", info.CreateTime); return hash;
}

3、业务逻辑层的实现分析

分析完成了数据访问层的接口和实现类后,我们来进一步看看业务逻辑层的实现分析,由于数据访问层的本意是基于特定的数据库实现,因此业务逻辑层就是抽象不同的数据库,让它们根据配置,指向不同的数据库实现类,从而实现多数据库的支持。

namespace WHC.TestProject.BLL
{
/// <summary>
/// 客户信息
/// </summary>
public class Customer : BaseBLL<CustomerInfo>
{
public Customer() : base()
{
base.Init(this.GetType().FullName, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
}
}
}

业务逻辑层的代码也很简单,在构造函数里面Init一下即可,之所以使用这个Init操作,其实为了确定BLL层的业务对象名称和指定在哪个程序集里面进行构造的需要,让给基类进行必要的创建工作。

在BaseBLL的Init函数里面,我们根据子类传入的相关参数,由于我们约定了数据访问类的命名空间,因此只根据数据库配置的不同需要,替换部分名称,就可以具体的构造出一个数据访问类了。

            #region 根据不同的数据库类型,构造相应的DAL层
AppConfig config = new AppConfig();
string dbType = config.AppConfigGet("ComponentDbType");
if (string.IsNullOrEmpty(dbType))
{
dbType = "sqlserver";
}
dbType = dbType.ToLower(); string DALPrefix = "";
if (dbType == "sqlserver")
{
DALPrefix = "DALSQL.";
}
else if (dbType == "access")
{
DALPrefix = "DALAccess.";
}
else if (dbType == "oracle")
{
DALPrefix = "DALOracle.";
}
else if (dbType == "sqlite")
{
DALPrefix = "DALSQLite.";
}
else if (dbType == "mysql")
{
DALPrefix = "DALMySql.";
}
#endregion this.dalName = bllFullName.Replace(bllPrefix, DALPrefix);//替换中级的BLL.为DAL.,就是DAL类的全名
baseDal = Reflect<IBaseDAL<T>>.Create(this.dalName, dalAssemblyName);//构造对应的DAL数据访问层的对象类

这样精确构造出来的数据库访问访问对象,并把它转换为基类接口,那么就可以在BaseBLL类里的基类接口进行调用了。

而构造业务对象,通过BLLFactory<T>的泛型工厂,更能够精确构造出对应的业务对象类,这样构造出来的对象具有强类型,非常方便使用。

以上就是业务逻辑层,数据访问层和数据访问接口层的设计关系,为了高效进行开发工作,我们一定要使用强类型的接口调用,这样可以大大减少出错机会,而返回的基类接口,由于传入了特定的具体类型T,也能够构造出强类型的列表或者对象。因此,合理利用泛型,能够是我们的开发体验更加美好,更加高效。

循序渐进开发WinForm项目(2)--项目代码的分析的更多相关文章

  1. 循序渐进开发WinForm项目(6)--开发使用混合式Winform模块

    1.Winform数据访问模式定义 传统的Winform程序模块:用于传统的数据库通讯获取数据,这种方式获取数据,方便快捷,可以用于常规的业务系统的场景,用于单机版软件或者基于局域网内的业务系统软件. ...

  2. 循序渐进开发WinForm项目(5)--Excel数据的导入导出操作

    随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了. 其实也许我 ...

  3. 循序渐进开发WinForm项目(4)--Winform界面模块的集成使用

    随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了. 其实也许我 ...

  4. 循序渐进开发WinForm项目(3)--Winform界面层的项目设计

    随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了. 其实也许我 ...

  5. 循序渐进开发WinForm项目(1) --数据库设计和项目框架的生成

    随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了. 其实也许我 ...

  6. 如何快速开发Winform应用系统

    在实际的业务中,往往还有很多需要使用Winform来开发应用系统的,如一些HIS.MIS.MES等系统,由于Winform开发出来的系统界面友好,响应快速,开发效率高等各方面原因,还有一些原因是独立的 ...

  7. Vue项目开发最新、最全代码规范文档

    Vue项目开发最新.最全代码规范文档 2019年02月21日 10:43:49 yw00yw 阅读数 337   一. 目录结构 |— build 构建脚本目录 |— build.js 生产环境构建( ...

  8. DevExpress控件开发常用要点(项目总结版)

    使用DevExpress控件来做项目开发已经有很长一段时间了,在摸索开发到客户苛刻要求的过程中,其中碰到过很多问题需要解决的,随着一个个问题的解决,也留下很多对DevExpress控件的使用经验及教训 ...

  9. MVC5 网站开发之二 创建项目

    昨天对项目的思路大致理了一下,今天先把解决方案建立起来.整个解决包含Ninesky.Web.Ninesky.Core,Ninesky.DataLibrary等3个项目.Ninesky.Web是web应 ...

随机推荐

  1. Console中加入招聘等个性化信息

    try { if (window.console && window.console.log) { console.log("%c XX息科技 ", "f ...

  2. ubuntu tomcat 部署java web

    1,安装jdk apt-get install openjdk-7-jdk 2,下载tomcat.解压到对应的文件夹 3,将xxx.war放入到 tomcat下的  webapp目录下(此目录下不要有 ...

  3. (笔记)Linux内核学习(十)之虚拟文件系统概念

    虚拟文件系统 虚拟文件系统:内核子系统VFS,VFS是内核中文件系统的抽象层,为用户空间提供文件系统相关接口: 通过虚拟文件系统,程序可以利用标准Linux文件系统调用在不同的文件系统中进行交互和操作 ...

  4. 【总结】编写自己的JDBC框架

    一.数据库连接池: 在一般用JDBC 进行连接数据库进行CRUD操作时,每一次都会: 通过:java.sql.Connection conn = DriverManager.getConnection ...

  5. JS - Constructor还可以这样用

    JS中Constructor好用法: 即在只知道一个对象实例的情况下(不知道对象名),重新初始化一个新实例: function Person( firstname, lastname, age ) { ...

  6. Zynq学习笔记(1)

    做硬件的第一个实例,一般当然是LED点灯啦~ 硬件:ZedBoard 软件:ISE 14.7 1.新建工程 2.选择平台 3.新建完成后,输入如下代码: `timescale 1ns / 1ps // ...

  7. iBatis.Net(C#)系列Demo源码

    iBatis.Net(C#)系列一:简介及运行环境源码  [下载] iBatis.Net(C#)系列二:SQL数据映射源码 [下载] iBatis.Net(C#)系列三:数据库查询源码  [下载]

  8. Ubuntu下的杀毒

      Ubuntu 11.04 杀毒软件ESET NOD32   Linux防病毒,并不代表没有病毒,只是数量过少.因技术精英发现漏洞后即时打补丁,病毒很少. 有兴趣的同学可以尝试下Ubuntu 11. ...

  9. wow 各职业体验(pvp)

    玩过职业 近战 武器战,冰DK,惩戒骑,增强萨,踏风 法系远程 鸟德,痛苦术,火法,奥法 治疗 奶德,奶骑,奶萨 三板甲职业就冰DK 最轻松,增强萨操作最频繁 机动性最好就武器战,踏风最差的,踏风群攻 ...

  10. MSSQL 之事务订单存储过程

    1. 赋值   set  或者 select 运算符 2.全局,局部变量区别,生命域 (全局变量用户不能定义) 3.@@identity  返回最后插入行的标识列的列值. 4.delete 只删除了数 ...