ASPNET AdventureWorks贸易系统分析
AdventureWorks贸易系统是一个使用N层架构和ASPNET 技术创建的Web站点该站点实现了贸易系统的部分功能在实现过程中重点使用了一些集成可重用组件这应该是大家阅读的重点所在本系列文章包括篇第一篇简单介绍一下系统概况和数据库设计第二篇讲解数据访问层的实现第三篇说明构建Web站点的方法通过这些内容读者将学习和实践多方面的知识例如N层架构应用使用数据访问应用程序块创建数据访问层使用泛型集合实现数据绑定使用企业库的异常处理块统一处理异常母版页应用等等
业务过程
AdventureWorks贸易系统实现了贸易系统的部分功能例如产品类别的显示等等有关该系统的功能读者可通过下面所描述的业务过程来了解AdventureWorks系统的业务过程包括
产品类别显示过程该过程允许用户显示AdventureWorks数据库中包括的所有类别用户可单击所显示类别列表中的特定类别以便显示所有相关的子类别
产品子类别显示过程在获得类别列表后接着可以显示所选中类别的所有子类别
产品显示过程通过这个过程可显示每个子类别中的产品列表单击特定子类别可获取该产品子类别包括的产品列表
正如读者看到的这些过程非常简单因为本实例主要关注的是集成可重用组件例如数据访问块异常管理块将数据库表转换为对象的泛型转换创建和利用存储过程等下面介绍一下系统架构方面的内容
系统架构
图说明了贸易系统的架构
数据库设计
既然大家已经了解了包括的业务过程那么下面将讲解实现解决方案所需的各个构造块为达到本实例目的实例余下部分的讨论将分为()数据库设计()实现CLR存储过程()实现数据访问和业务逻辑组件()实现Web站点下面首先介绍数据库方面的设计
本实例使用的AdventureWorks数据库包括多个表但是该实例仅使用了其中的三个表ProductCategoryProductSubcategory和Product以下说明表的结构首先是ProductCategory表
ProductSubcategory表定义如下
下表说明了Product表的结构
下一步是说明创建操作这些结构的存储过程
实现CLR存储过程
SQL Server 最优雅的功能之一是集成NET CLR集成CLR的SQL Server在多个重要的方面扩展了SQL Server功能利用这种集成可创建数据库对象(例如存储过程)用户定义函数以及使用现代面向对象语言(例如VBNET和C#)创建触发器为达成本实例目的将说明使用C#创建存储过程的方法
首先在Visual Studio 中以Visual Studio 作为编程语言创建一个新的名为AdventureWorksDatabaseObjects的SQL Server项目由于创建的是数据库项目所以需要关联数据源与项目在创建项目的同时Visual Studio将要求开发人员要么选择现有数据库引用要么添加新数据库引用选择AdventureWorks作为数据库一旦创建项目则在项目菜单中选择添加存储过程选项在添加新项对话框中输入StoredProcedurescs接着单击添加按钮在创建类之后可根据以下内容修改类中代码
示例实现CLR存储过程
using System;
using SystemData;
using SystemDataSqlClient;
using SystemDataSqlTypes;
using MicrosoftSqlServerServer;
public partial class StoredProcedures
{
[MicrosoftSqlServerServerSqlProcedure]
public static void GetProductCategories()
{
using (SqlConnection connection = new SqlConnection(context connection=true))
{
connectionOpen();
string sqlCommand = Select ProductCategoryID Name rowguid +
ModifiedDate from ProductionProductCategory;
SqlCommand command = new SqlCommand(sqlCommand connection);
SqlDataReader reader = commandExecuteReader();
SqlContextPipeSend(reader);
}
}
[MicrosoftSqlServerServerSqlProcedure]
public static void GetProductSubcategories(int productCategoryID)
{
using (SqlConnection connection = new SqlConnection(context connection=true))
{
connectionOpen();
string sqlCommand = Select ProductSubcategoryID ProductCategoryID Name + rowguid ModifiedDate from ProductionProductSubcategory + Where ProductCategoryID = + productCategoryID;
SqlCommand command = new SqlCommand(sqlCommand connection);
SqlDataReader reader = commandExecuteReader();
SqlContextPipeSend(reader);
}
}
[MicrosoftSqlServerServerSqlProcedure]
public static void GetProducts(int productSubcategoryID)
{
using (SqlConnection connection = new SqlConnection(context connection=true))
{
connectionOpen();
string sqlCommand = Select ProductID Name ProductNumberMakeFlag + FinishedGoodsFlag Color SafetyStockLevel ReorderPointStandardCost + ListPrice Size SizeUnitMeasureCode WeightUnitMeasureCode + WeightDaysToManufacture ProductLineClass Style + ProductSubcategoryID ProductModelIDSellStartDateSellEndDate + DiscontinuedDate rowguid ModifiedDate from ProductionProduct + Where ProductSubcategoryID = + productSubcategoryIDToString();
SqlCommand command = new SqlCommand(sqlCommand connection);
SqlDataReader reader = commandExecuteReader();
SqlContextPipeSend(reader);
}
}
};
在示例中首先导入所需命名空间接着声明StoreProcedures类导入的重要命名空间之一是MicrosoftSqlServerServer该命名空间包括两个针对内部过程提供程序的重要类
SqlContext该类封装了为在SQL Server 中执行内部过程所需的扩展对象另外该类还提供了事务和数据库连接它们是常规执行环境中的一部分
SqlPipe该类通常可将表格式结果和消息发送给客户端就概念而言该类与ASPNET中的Response类相似因此可用于将消息发送给调用者
StoredProcedures类包括三个静态方法GetProductCategories()GetProductSubcategories()和GetProducts()正如名称暗示GetProductCategories()方法仅从AdventureWorks数据库中返回所有类别信息GetProductSubcategories()方法可返回输入特定类别的子类别信息GetProducts()方法可返回输入特定产品子类别的所有产品信息以下内容将详细讲解GetProductCategories()方法
在GetProductCategories()方法内部首先使用SqlConnection对象数据库连接注意传递给SqlConnection对象构造函数的连接字符串设置为context connection=true这意味着使用登录用户的上下文打开数据库连接
using (SqlConnection connection = new SqlConnection(context connection=true))
此时使用Open()方法打开数据库连接
connectionOpen();
然后设置将要执行的SQL命令在这种情况下从ProductCategory表中获取所有记录
string sqlCommand = Select ProductCategoryID Name rowguid ModifiedDate from + ProductionProductCategory;
接着将SQL查询语句和SqlConnection对象作为参数传递给SqlCommand类的构造函数以便创建SqlCommand对象实例
SqlCommand command = new SqlCommand(sqlCommand connection);
此后通过调用SqlCommand对象的ExecuteReader()方法执行SQL查询
SqlDataReader reader = commandExecuteReader();
使用SqlPipe对象将表格式结果和消息返回给客户端这是通过SqlPipe类的Send()方法来实现
SqlContextPipeSend(reader);
Send()方法提供了多种重载以便通过管道将数据发送给调用方应用程序
StoredProcedures类中所有方法都使用Send()方法来将表格式结果以SqlDataReader对象格式发送给客户应用程序由于GetProductSubcategories()和GetProducts()与GetProductCategories()方法的实现非常相似因此不会对前二者进行详细讲解
既然创建了存储过程那么就可以非常简单和直接的应用它们了在应用之前需要首先生成项目为了生成项目可在Visual Studio 的菜单中选择生成→生成AdventureWorksDatabaseObjects如果出现编译错误则将显示在错误列表面板中一旦生成项目那么就能够通过选择菜单中的生成→部署AdventureWorksDatabaseObjects项来将其部署到SQL Server中这样不仅在SQL Server中注册了程序集而且还在SQL Server中部署了存储过程当存储过程部署到SQL Server后接着可以在数据访问层调用它这些内容将在下一节讲解
在执行存储过程之前记住使用SQL Server Management Studio执行以下代码以便在SQL Server中执行受管代码
EXEC sp_configure clr enabled ;
RECONFIGURE WITH OVERRIDE;
GO
虽然该实例使用Visual Studio创建受管存储过程但是开发人员还是能够轻松使用文本编辑器(例如记事本)获得相同的结果
另外可能有些读者会感到疑惑到底何时使用TSQL何时使用受管代码呢?这个问题的答案很简单受管代码比TSQL更加适合实现复杂的执行逻辑同时它对于完成许多复杂任务都具有广泛支持包括字符串处理和正则表达式TSQL比较适合实现具有少量或者非过程性逻辑的数据访问的情况本实例中的存储过程很简单最好使用TSQL编写然而却使用了受管代码的方法这主要是为了说明创建和使用受管存储过程的方法
小结
本文对贸易系统的业务过程系统架构数据库设计和CLR存储过程的实现进行了介绍贸易系统与其他很多实例不同的是这个实例充分利用了集成重用块EntLib尤其是在实现数据访问异常处理等方面这可能是读者应该重点学习和关注的方面在下一篇文章中将介绍实现数据访问层的方法