Microsoft PetShop 3.0 设计与实现 分析报告―――数据访问层

** Microsoft PetShop 3.0 ** ** 设计与实现-- ** ** 数据访问层 ** ** **

最近对多层设计实现和 .Net 产生了兴趣,从而研究了一下比较著名的多层范例程序―― PetShop ,现在的版本是 3.0 ,和以前的版本从设计上已有一定的区别,应该是和 Java 的 Petshop 设计相当。

关于一些 Microsoft PetShop 的来由、如何安装,所表现业务流程,数据库表结构等基本的信息的资料请大家参考下面文章

http://msdn.microsoft.com/library/en-us/dnbda/html/bdasamppet.asp

另外建议先看一下这篇文章:

http://msdn.microsoft.com/library/en-us/dnbda/html/petshop3x.asp

(如有格式问题本文可到 http://www.surfsky.com/bbs/myfiles/MSPetShop3.0%20Report.doc

下载)

本文将以设计和实现紧密结合的方式来分析,这也是我们广大实践型的软件开发人员的风格。先看一下设计图和具体实现 VS.NET 工程的表格。

** MSPetShop 3.0 ** ** 系统结构图: ** ** **

从图中可以看到系统大体分为 Presentation,Business Logic,Data Access 三层,每层中又有子层。每层(也包括子层)各司其职,又互相协作,本文顺序以此图为准,从下到上分析。

对应上图,具体的 .NET Project 实现列表(借用 MS 文章中的列表不用翻译了吧)

** Project **

|

** Purpose **

---|---

BLL

|

Home for business logic components

ConfigTool

|

Administration application used to encrypt connection strings and create event log source

DALFactory

|

Classes used to determine which database access assembly to load

IDAL

|

Set of interfaces which need to be implemented by each DAL implementation

Model

|

Thin data classes or business entities

OracleDAL

|

Oracle specific implementation of the Pet Shop DAL which uses the IDAL interfaces

Post-Build

|

Project to run post compile actions such as adding assemblies to the GAC or COM+

Pre-Build

|

Project to remove assemblies from the GAC or unregister assemblies from COM+

SQLServerDAL

|

Microsoft SQL Server specific implementation of the Pet Shop DAL which uses the IDAL interfaces

Utility

|

Set of helper classes including a wrapper for the DPAPI

Web

|

Web pages and controls

Solution Items

|

Miscellaneous items used to build the application such as Pet Shop.snk key file used to sign application assemblies

另外我写这篇文章时是一边看源码一边写,所以建意大家最好安装一个 Petshop3 ,因为时间仓促,水平有限,如我有不对之处请给我发 Email 更正。 email:[email protected] qq:364941

首先我们来看一下 DAL 层。

** 一: ** ** Data Access Layer: **

1 PetShop.Utility如下图:(上表中Utility为其实现工程)

正如上表所描述,这个名字空间有两个类一个是 ConnectionInfo 用于加密解密数据库连接信息,另一个 DataProtector 调用了 Crypt32.dll和kernel32.dll实现一些底层数据安全操作,这个类要在下面的PetShop.XXXDAL名字空间中调用,可见Petshop.Utility只是起到的是数据访问辅助工具的作用。

2 PetShop.SQLServerDAL ――系统结构图中DAL层中的SqlServer DAL子层实现

SqlHelper 类实际上是封装了关于此系统中数据库操作访问的一些常用功能,其中它还会调用上面的 PetShop.Utility 中的 ConectionInfo 类方法加密解密连接字符串,如: ConnectionInfo.DecryptDBConnectionString方法。SqlHelper类是基于Microsoft Data Access Application Block for .NET。这个东西是用来帮助用户更好的在.NET的访问数据。如MS一段话:Are you involved in the design and development of data access code for .NET-based applications? Have you ever felt that you write the same data access code again and again? Have you wrapped data access code in helper functions that let you call a stored procedure in one line? If so, the Microsoft ® Data Access Application Block for .NET is for you。其实可以自已写一个类似SqlHelper的东西,以实现一般化的对数据库的操作,以在各项目中重用,当然也可以使用现在的MS为你做好的这个SqlHelper或是Microsoft ® Data Access Application Block for .NET,避免不同项目中总是写同样的重复的数据库访问程序。有时间最好还是看一下SqlHelper的具体程序实现思路以及所提到的那个Microsoft Data Access Application Block for .NET。不过这里我们的SqlHelper应该只是部分实现。更全面信息请参看:http://msdn.microsoft.com/library/en-us/dnbda/html/daab-rm.asp

Account类对用户帐户进行操作如Insert,Update,SignIn,其中这些对数据库的操作,使用了上面的SqlHelper类来实现。另外Inventory和Order,Product,Profile和Account类的都是同样对数据库相关表进行操作,程序风格一致,这些类中对数据库的操作都是通过此名字空间下的SqlHelper类进行的,例如,下面语句:

private const string SQL_INSERT_SIGNON = "INSERT INTO SignOn VALUES (@UserId, @Password)";

private const string PARM_USER_ID = "@UserId";

private const string PARM_PASSWORD = "@Password";

来定义一个 sql语句,以及声明其中可变参数,然后像下面这样用SqlHelper类的合适的方法执行:

SQLHelper.ExecuteNonQuery(trans, CommandType.Text, SQL_INSERT_SIGNON, signOnParms);

最后在 SQLHelper.ExecuteNonQuery实现中,再调用ado.net中的相关类最终执行对数据库的操作,可见SqlHelper在这里又封装了一下ado.net相关类以优化数据操作。正如SqlHelper.cs中注释提示: The SqlHelper class is intended to encapsulate high performance, scalable best practices for common uses of SqlClient. 下面是SqlHelper. ExecuteNonQuery的实现内容:

public static int ExecuteNonQuery( string connString, CommandType cmdType, string cmdText, params SqlParameter[] cmdParms) {

//注:运行时cmdText的实参就是SQL_INSERT_SIGNON

SqlCommand cmd = new SqlCommand();

using (SqlConnection conn = new SqlConnection(connString)) {

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

int val = cmd.ExecuteNonQuery();

cmd.Parameters.Clear();

return val;

}

}

另外 Inventory和Order,Product,Profile和Account类的声明都是像 public class Account : IAccount这样实现某个相关的接口,像IAccount这样的接口是在PetShop.IDAL中声明的,见后面介绍。

3 PetShop.OracleDAL ―――系统结构图中 DAL层的OracleDAL子层实现

个人认为结构应该同上面的 PetShop. SQLServerDAL,另外SqlHelper变成了OraHelper,在OraHelper中当然具体实现了对特定的Oracle数据库的联接操作,看一下源程序很明显原来的 SqlCommand cmd = new SqlCommand(); 变成了OracleCommand cmd = new OracleCommand();。

注意一下:在系统结构图中的 DAL层还有两个XXX DAAB的子层,它们对应的实现在哪里呢? 下面对应一下:

以下是左边是图中 DataAccessLayer的各部分,右边是具体实现所在名字空间或类

SqlServer DAL――PetShop.SQLServerDAL名字空间

Sql DAAB――PetShop.SqlServerDal.SqlHelper类

Oracle DAL――PetShop.OracleDAL名字空间

Oracle DAAB――PetShop.OracleDAL.OraHelper类

4 PetShop.IDAL 数据访问接口――对应系统结构图中DAL Interface

接口是一种系列‘功能’的声明或名单,接口没有实现细节,如下接口 IAccount 定义也可以看出 IAccount 只有声明:

using System;

using PetShop.Model;

namespace PetShop.IDAL

{

// Inteface for the Account DAL

public interface IAccount

{

// Authenticate a user

AccountInfo SignIn( string userId, string password);

/// Get a user's address stored in the database

AddressInfo GetAddress( string userId);

/// Insert an account into the database

void Insert(AccountInfo account);

/// Update an account in the database

void Update(AccountInfo Account);

}

}

您只需要调用接口,而不用管接口是如何实现的 那么接口没有实现,调用它有什么用?实际上接口的实现是由某个类来做的,那么这里的 IAccount接口是由PetShop.SqlServerDAL.Account类或是PetShop.OracleDAL.Account类来实现的,从他们的定义可以看到:

public class Account : IAccount { …… .}

为什么是两个类都实现同一接口又是‘或’呢?因为这里使用接口的目的就是为了统一‘外观’,当上层 BLL层调用此接口方法时不用知道这个接口由哪个类实现的。那谁来确定使用哪个类的实现?请再看下面。

( PetShop.IDAL下的其它接口和IAccount一样,故在此略过。)

5 PetShop.DALFactory 数据访问工厂

工厂模式是设计模式的一种,以我理解就像 Factory这个词一样,对于用户来说,工厂里产品如何生产的你不用知道,你只要去用工厂里生产出来的东西就可以了。MSPetShop3.0用工厂模式来实现了对SqlServer和Oracle数据库访问的操作,而用户( business Logic Layer )不用知道也不用关心后台用的是哪一种数据库,它只要用接口就行了,接口中定义了要用的方法,当调用接口时会根据具体的情况再去调用底层数据访问操作。而现在这个 DALFactory就是关键,当BLL层要操作数据库时,DALFactory会根据具体情况再去使用本文上面介绍的SqlServerDAL和OracleDAL中的一个。这样系统上层只管调用,而下层来实现细节,上级只管发号施令,下级去干活。对于上层来说实现细节被隐藏了。

那么 DALFactory是如何决定应该用SqlServerDAL还是用OracleDAL的呢?我们接着分析。

以下是PetShop.DALFactory.Account类的实现:

namespace PetShop.DALFactory {

///

1<summary>
2
3///  Factory implementaion for the Account DAL object 
4
5///  </summary>

public class Account

{

public static PetShop.IDAL.IAccount Create() //<<<< ß ----这里返回接口

{

/// Look up the DAL implementation we should be using

string path = System.Configuration.ConfigurationSettings.AppSettings["WebDAL"];

&

Published At
Categories with Web编程
Tagged with
comments powered by Disqus