一、Petshop4解决方案 Petshop4代码和数据库:下载 Petshop4详解:下载 安装要求: Operating System: Windows XP SP2 or Windows Server 2003 Microsoft.NET Framework 2.0 Microsoft SQL Server 2005, SQL Server Express, or Oracle 10g Microsoft Internet Explorer 6 or greater Microsoft Visual Studio® .NET 2005 后续步骤: 1、手动编译:运行<Pet Shop 4 Install Folder>\Build.bat,将编译整个解决方案。 2、用VisualStudio自带的浏览器运行: (1)打开解决方案。Start Menu | All Programs | Microsoft .NET Pet Shop 4 | Petshop.sln (2)设置Web项目为启动项目 (3)右键单击“解决方案”节点,点“构建” (4)打开Web项目,右键单击“Default.aspx”,点“在浏览器中查看” (5)如果安装了Membership/Profile数据库,系统会创建12个帐号,即demo, AdamBarr, KimAbercrombie,RobYoung, TomYoutsey, GaryWYukish, RobCaron, KarinZimprich, RandallBoseman, KevinKennedy, DianeTibbott, 或GarrettYoung。密码是pass@word1 3、运行在windows server 2003的IIS上 (1)先解密web.config文件中的连接串。 点击<Pet Shop 4 Install Folder>\DecryptWebConfig.bat解密连接串。不解密的话IIS会报错。 (2)由于2003IIS的.net版本最高为2.0。笔者在编译Petshop的Web项目时,需要设置属性页的“目标Framework”为2.0。如下图: (3)视情况修改web.config中的数据库连接串,确保能正确连上数据库。 (4)将Web文件夹实施到IIS中。 运行效果如下: 二、Petshop4体系结构 三、Petshop三层结构总结 1、表记录 --> 实体类 将Category数据库表中的单个记录定义为一个类(叫产品实体),类的属性就是数据库表中每个记录的字段。产品实体承载数据表的记录。所有实体类的集合形成了Petshop中Model模块。Category实体的代码如下所示: using System; namespace PetShop.Model { public class CategoryInfo { //属性 private string id; private string name; private string description; public CategoryInfo() { } public CategoryInfo(string id, string name, string description) { this.id = id; this.name = name; this.description = description; } // 属性的get操作 public string Id { get { return id; } } public string Name { get { return name; } } public string Description { get { return description; } } } } 2、记录的删改增查等操作 -> 转换成访问数据库的函数 -> 函数组织到一起形成类 3、-> 由于数据库多样性&访库操作的一致性(不外乎删改增查操作) -> 抽象出一个接口 数据访问层采用“面向接口编程”思想,抽象出来的IDAL模块,脱离了与具体数据库的依赖,从而使得整个数据访问层利于数据库迁移。SQLServerDAL和OracleDAL模块均实现IDAL模块的接口,其中包含的逻辑就是对数据库的Select,Insert,Update和Delete操作。因为数据库类型的不同,对数据库的操作也有所不同,代码也会因此有所区别。 using System; using PetShop.Model; using System.Collections.Generic; namespace PetShop.IDAL{ /// <summary> /// 类别数据访问层的接口 /// </summary> public interface ICategory { /// <summary> /// 此方法用于获得所有宠物类别 /// </summary> /// <returns>此接口用于生成普通类别的模型集合</returns> IList<CategoryInfo> GetCategories(); /// <summary> /// 获取某个宠物类别的信息 /// </summary> /// <param name="categoryId">宠物的唯一标示符</param> /// <returns>描述一个宠物业务逻辑的实体类</returns> CategoryInfo GetCategory(string categoryId); } } 针对SQLServer数据库的实现 using System; using System.Data; using System.Data.SqlClient; using PetShop.Model; using PetShop.IDAL; using System.Collections.Generic; using PetShop.DBUtility; namespace PetShop.SQLServerDAL { public class Category : ICategory { // 声明静态变量 private const string SQL_SELECT_CATEGORIES = "SELECT CategoryId, Name, Descn FROM Category"; private const string SQL_SELECT_CATEGORY = "SELECT CategoryId, Name, Descn FROM Category WHERE CategoryId = @CategoryId"; private const string PARM_CATEGORY_ID = "@CategoryId"; /// <summary> /// 此方法用于获得所有宠物类别信息 /// </summary> public IList<CategoryInfo> GetCategories() { IList<CategoryInfo> categories = new List<CategoryInfo>(); //执行获取所有宠物类别的SQL语句 using(SqlDataReader rdr = SqlHelper.ExecuteReader(SqlHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_SELECT_CATEGORIES, null)) { while (rdr.Read()) { CategoryInfo cat = new CategoryInfo(rdr.GetString(0), rdr.GetString(1), rdr.GetString(2)); categories.Add(cat); } } return categories; } /// <summary> /// 根据提供的id ,获取指定的单个宠物类别信息 /// </summary> /// <param name="categoryId">宠物类别标识码d</param> /// <returns>单个宠物类别的详细资料</returns> public CategoryInfo GetCategory(string categoryId) { //设置一个返回值 CategoryInfo category = null; //创建一个参数 SqlParameter parm = new SqlParameter(PARM_CATEGORY_ID, SqlDbType.VarChar, 10); //绑定参数 parm.Value = categoryId; //执行查询 using (SqlDataReader rdr = SqlHelper.ExecuteReader(SqlHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_SELECT_CATEGORY, parm)) { if (rdr.Read()) category = new CategoryInfo(rdr.GetString(0), rdr.GetString(1), rdr.GetString(2)); else category = new CategoryInfo(); } return category; } /// <summary> /// 为创建宠物类别创建一个SqlCommand对象 /// </summary> /// <param name="id">宠物类别码</param> /// <returns>用于找回宠物类别的sql命令</returns> public static SqlCommand GetCommand() { return new SqlCommand(SQL_SELECT_CATEGORIES); } } } 针对Oracle数据库的实现 using System; using System.Data; using System.Data.OracleClient; using PetShop.Model; using PetShop.IDAL; using System.Collections.Generic; using PetShop.DBUtility; namespace PetShop.OracleDAL { public class Category : ICategory { // Static constants private const string SQL_SELECT_CATEGORIES = "SELECT CategoryId, Name, Descn FROM Category"; private const string SQL_SELECT_CATEGORY = "SELECT CategoryId, Name, Descn FROM Category WHERE CategoryId = :CategoryId"; private const string PARM_CATEGORY_ID = ":CategoryId"; /// <summary> /// Method to get all categories /// </summary> public IList<CategoryInfo> GetCategories() { IList<CategoryInfo> categories = new List<CategoryInfo>(); //Execute a query to read the categories using(OracleDataReader rdr = OracleHelper.ExecuteReader(OracleHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_SELECT_CATEGORIES, null)) { while (rdr.Read()) { CategoryInfo cat = new CategoryInfo(rdr.GetString(0), rdr.GetString(1), rdr.GetString(2)); categories.Add(cat); } } return categories; } /// <summary> /// Get an individual category based on a provided id /// </summary> /// <param name="categoryId">Category id</param> /// <returns>Details about the Category</returns> public CategoryInfo GetCategory(string categoryId) { //Set up a return value CategoryInfo category = null; //Create a parameter OracleParameter parm = new OracleParameter(PARM_CATEGORY_ID, OracleType.Char, 10); //Bind the parameter parm.Value = categoryId; //Execute the query using (OracleDataReader rdr = OracleHelper.ExecuteReader(OracleHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_SELECT_CATEGORY, parm)) { if (rdr.Read()) category = new CategoryInfo(rdr.GetString(0), rdr.GetString(1), rdr.GetString(2)); else category = new CategoryInfo(); } return category; } } } 4、到配置文件中做“决定” 用户如何决定用哪种访问数据的类来访问数据库?用户不必关心。因为这个决定写在配置文件web.config中了。迁移到另一种数据时,只需修改web.config,而不需要修改代码。 为了做到这一点,.NET用反射。代码如下: web.config如下: <?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <connectionStrings> <!-- SQL connection string for Profile database --> <add name="SQLProfileConnString" connectionString="server=(local);user id=sa;password=jazzking;database=MSPetShop4Profile;min pool size=4;max pool size=4;packet size=3072" providerName="System.Data.SqlClient"/> <!-- SQL connection string for Membership database --> <add name="SQLMembershipConnString" connectionString="server=(local);user id=sa;password=jazzking;database=MSPetShop4Services;min pool size=4;max pool size=4;packet size=3072" providerName="System.Data.SqlClient"/> <!-- SQL connection string for Inventory database lookup --> <add name="SQLConnString1" connectionString="server=(local);user id=sa;password=jazzking;database=MSPetShop4;min pool size=4;max pool size=4;packet size=3072" providerName="System.Data.SqlClient"/> <!-- SQL connection string for handling transactions on the Inventory database--> <add name="SQLConnString2" connectionString="server=(local);user id=sa;password=jazzking;database=MSPetShop4;min pool size=4;max pool size=4;packet size=1024" providerName="System.Data.SqlClient"/> <!-- SQL connection string for Orders database--> <add name="SQLConnString3" connectionString="server=(local);user id=sa;password=jazzking;database=MSPetShop4Orders;min pool size=4;max pool size=4;packet size=1024" providerName="System.Data.SqlClient"/> <!-- Oracle connection strings--> <add name="OraProfileConnString" connectionString="Data Source=localhost;user id=MSPETSHOPPROFILE;password=pass@word1;min pool size=4;max pool size=4" providerName="System.Data.OracleClient"/> <add name="OraMembershipConnString" connectionString="Data Source=localhost;user id=MSPETSHOPMEMBERSHIP;password=pass@word1;min pool size=4;max pool size=4" providerName="System.Data.OracleClient"/> <add name="OraConnString1" connectionString="Data Source=localhost;user id=MSPETSHOP;password=pass@word1;min pool size=4;max pool size=4" providerName="System.Data.OracleClient"></add> <add name="OraConnString2" connectionString="Data Source=localhost;user id=MSPETSHOP;password=pass@word1;min pool size=4;max pool size=4" providerName="System.Data.OracleClient"></add> <add name="OraConnString3" connectionString="Data Source=localhost;user id=MSPETSHOPORDERS;password=pass@word1;min pool size=4;max pool size=4" providerName="System.Data.OracleClient"></add> </connectionStrings> <appSettings> <!-- Pet Shop DAL configuration settings --> <!--设置数据库连接类型 value 此数据库联接类 --> <add key="WebDAL" value="PetShop.SQLServerDAL"/> <add key="OrdersDAL" value="PetShop.SQLServerDAL"/> <add key="ProfileDAL" value="PetShop.SQLProfileDAL"/> 对数据库中所有表的操作接口打成包方便统一访问,Petshop中叫数据库访问层工厂。如下: using System.Reflection; using System.Configuration; namespace PetShop.DALFactory { public sealed class DataAccess { // 查找我们将要使用的数据访问层 private static readonly string path = ConfigurationManager.AppSettings["WebDAL"]; //对照web.config,此时path的值为“PetShop.SQLServerDAL”。表示该系统使用了SQLServer数据库。 private static readonly string orderPath = ConfigurationManager.AppSettings["OrdersDAL"]; private DataAccess() { } //实现 CreateCategory 方法,用于创建Category类实例 public static PetShop.IDAL.ICategory CreateCategory() { string className = path + ".Category"; //利用反射技术,动态加载指定类型 return (PetShop.IDAL.ICategory)Assembly.Load(path).CreateInstance(className); } //实现 CreateInventory 方法,用于创建Inventory类实例 public static PetShop.IDAL.IInventory CreateInventory() { string className = path + ".Inventory"; return (PetShop.IDAL.IInventory)Assembly.Load(path).CreateInstance(className); } //实现 CreateItem 方法,用于创建Item类实例 public static PetShop.IDAL.IItem CreateItem() { string className = path + ".Item"; return (PetShop.IDAL.IItem)Assembly.Load(path).CreateInstance(className); } //实现 CreateOrder 方法,用于创建Order类实例 public static PetShop.IDAL.IOrder CreateOrder() { string className = orderPath + ".Order"; return (PetShop.IDAL.IOrder)Assembly.Load(orderPath).CreateInstance(className); } //实现 CreateProduct 方法,用于创建Product类实例 public static PetShop.IDAL.IProduct CreateProduct() { string className = path + ".Product"; return (PetShop.IDAL.IProduct)Assembly.Load(path).CreateInstance(className); } } } 以上是数据库访问层的内容 5、业务逻辑层必须独立 既然是逻辑,那么该层处理的内容可以说基本上是一些if...else等等。另外,业务逻辑层需要访问数据库时,是通过“数据库访问层工厂”进行的,不再是直接在里面傻傻的写sql语句。 using System.Collections.Generic; using PetShop.Model; using PetShop.IDAL; namespace PetShop.BLL { /// <summary> /// 实现有关宠物类别的业务逻辑类 /// </summary> public class Category { //从数据访问层工厂类得到一个种类的数据访问层的实例 //确保这个静态可以在初始化后缓存数据访问层 private static readonly ICategory dal = PetShop.DALFactory.DataAccess.CreateCategory(); ////通过数据访问层工厂访问数据库 public IList<CategoryInfo> GetCategories() { return dal.GetCategories(); } public CategoryInfo GetCategory(string categoryId) { // 确认输入参数 if (string.IsNullOrEmpty(categoryId)) ///逻辑层的if语句 return null; //通过类别ID到数据访问层去查询 return dal.GetCategory(categoryId); } } } 四、Global.asax和web.config Global.asax:http://hi.baidu.com/mycolorwind/blog/item/45384980228cbfdf9023d960.html global.asax详解:http://club.topsage.com/thread-485397-1-1.html global.asax介绍:http://blog.csdn.net/suntanyong88/article/details/6009278 关于global.asax总结经验:http://hi.baidu.com/chinadaima/blog/item/32e0c9ef53b81f32adafd566.html web.config详解:http://blog.csdn.net/zhoufoxcn/article/details/3265141 数据连接串:http://www.cnblogs.com/zlytu/archive/2011/11/22/2258364.html Petshop分析:http://www.cnblogs.com/sunfishlu/archive/2008/02/02/1062049.html 走进.net架构:http://www.cnblogs.com/yanyangtian/category/265762.html