现在我就开始进入学习之路的第二步——Data Access模块,这个模块是企业库中被使用频率最高的模块,它很好的封装了数据库操作应用,为我们进行多数据库系统开发提供了便利,只需更改配置文件就 可以很快的切换数据库访问(可惜还是要重写SQL语句,没法和ORM比)。
下面是我在配置企业库的时候碰到问题,如果没有碰到可以略去不看(可能有点小白)
注意:此处切换数据库配置必须是计算机中已经安装好相应的数据库访问模块,如需要进 行从MS SQL向SQLite数据库的变更时,计算机中必须安装好SQLite数据库访问模块(在这里我就碰到了这个问题,原来我机器上在VS2008开发时已经 安装过SQLite数据库访问模块,但是新装了VS2010,在VS2010引用对话框中也能访问到在VS2008安装的SQLite(但是在企业库 5.0配置器中无法查看到SQLite),但是发现更改企业库的配置文件后无法访问SQLite数据库,尝试了很多方法都没用,结果死马当活马医又重新装 了一遍SQLite数据库访问模块再重新打开企业库配置器就可以看到SQLite数据库了(所以请确保在企业库编辑器中可以查看到要切换的数据库,否则可能导致无法访问数据库)。看下图:
回归正题,这次的学习由于VS2010发布了,而且企业库5.0也都支持.NET4.0,所以决定企业库的学习之路采用VS2010进行学习(顺便熟悉下.NET4的特性,毕竟公司的项目不可能立马转移到.NET4.0的,现在就当练手吧)
好了,现在就开始进行第2步的学习了,首先看下项目的结构:
项目采用仿MS PetShop架构,如不了解此架构可以到此查看了解:PetShop的系统架构设计
其中DAL和DALSQLite层对应MS SQL和SQLite数据库,Helper为整个项目的帮助器
现在来具体了解下DAL层
在DAL层中引用了Helper,IDAL,EnterpriseLibrary.Common和EnterpriseLibrary.Data这4个项目,其中Helper项目中有个DBHelper.cs,用于获取当前的数据对象,其代码如下(采用了C#4.0的语法特性,默认参数,数据库对象名默认为空,这样则会调用企业库默认的数据库对象,同时也可以在调用的时候赋值,这样则根据传递过来的数据库对象名来创建数据库,通过这个参数我们将原来需要重载的2个方法才能实现合并成了一个方法)
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; using Microsoft.Practices.EnterpriseLibrary.Data; namespace EntLibStudy.Helper { public static class DBHelper { /// <summary> /// 获取数据库对象 /// </summary> /// <param name="name">数据库实例名(默认name为空,调用默认数据库实例)</param> /// <returns>数据库对象</returns> public static Database CreateDataBase(string name = "") { //return DatabaseFactory.CreateDatabase(name); return EnterpriseLibraryContainer.Current.GetInstance<Database>(name); } } }
在DAL层中则引用Helper来获取数据库对象,进行数据库操作,我们现在来看下具体的数据库访问类编写代码,学员操作类:
using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Linq; using System.Text; using Microsoft.Practices.EnterpriseLibrary.Data; using EntLibStudy.Model; using EntLibStudy.Helper; namespace EntLibStudy.DAL { public class StudentService : EntLibStudy.IDAL.IStudentService { /// <summary> /// 新增学生 /// </summary> /// <param name="student">学生对象</param> /// <returns></returns> public int Add(Student student) { Database db = DBHelper.CreateDataBase(); StringBuilder sb = new StringBuilder(); sb.Append("insert into Student values(@ClassId,@SID,@Password,@Name,@Sex,@Birthday,@IsAdmin);SELECT @@IDENTITY;"); DbCommand cmd = db.GetSqlStringCommand(sb.ToString()); db.AddInParameter(cmd, "@ClassId", DbType.String, student.ClassId); db.AddInParameter(cmd, "@SID", DbType.String, student.Sid); db.AddInParameter(cmd, "@Password", DbType.String, student.Password); db.AddInParameter(cmd, "@Name", DbType.String, student.Name); db.AddInParameter(cmd, "@Sex", DbType.Int32, student.Sex); db.AddInParameter(cmd, "@Birthday", DbType.DateTime, student.Birthday); db.AddInParameter(cmd, "@IsAdmin", DbType.Int32, student.IsAdmin); int id = Convert.ToInt32(db.ExecuteScalar(cmd)); return id; } /// <summary> /// 更新 /// </summary> /// <param name="classInfo">学生对象</param> /// <returns>是否成功</returns> public bool Update(Student student) { Database db = DBHelper.CreateDataBase(); StringBuilder sb = new StringBuilder(); sb.Append("update Student set ClassId=@ClassId,"); sb.Append("SID=@SID,"); sb.Append("Password=@Password,"); sb.Append("Name=@Name,"); sb.Append("Sex=@Sex,"); sb.Append("Birthday=@Birthday,"); sb.Append("IsAdmin=@IsAdmin "); sb.Append(" where ID=@ID"); DbCommand cmd = db.GetSqlStringCommand(sb.ToString()); db.AddInParameter(cmd, "@ClassId", DbType.String, student.ClassId); db.AddInParameter(cmd, "@SID", DbType.String, student.Sid); db.AddInParameter(cmd, "@Password", DbType.String, student.Password); db.AddInParameter(cmd, "@Name", DbType.String, student.Name); db.AddInParameter(cmd, "@Sex", DbType.Int32, student.Sex); db.AddInParameter(cmd, "@Birthday", DbType.DateTime, student.Birthday); db.AddInParameter(cmd, "@IsAdmin", DbType.Int32, student.IsAdmin); db.AddInParameter(cmd, "@ID", DbType.Int32, student.Id); return db.ExecuteNonQuery(cmd) > 0 ? true : false; } /// <summary> /// 删除 /// </summary> /// <param name="id">学生ID</param> /// <returns>是否成功</returns> public bool Delete(int id) { Database db = DBHelper.CreateDataBase(); StringBuilder sb = new StringBuilder(); sb.Append("delete from Student "); sb.Append(" where ID=@ID"); DbCommand cmd = db.GetSqlStringCommand(sb.ToString()); db.AddInParameter(cmd, "@ID", DbType.Int32, id); return db.ExecuteNonQuery(cmd) > 0 ? true : false; } /// <summary> /// 根据学生ID查询学生对象 /// </summary> /// <param name="id">学生ID</param> /// <returns></returns> public Student SelectById(int id) { Student student = null; Database db = DBHelper.CreateDataBase(); StringBuilder sb = new StringBuilder(); sb.Append("select * from Student "); sb.Append(" where ID=@ID"); DbCommand cmd = db.GetSqlStringCommand(sb.ToString()); db.AddInParameter(cmd, "@ID", DbType.Int32, id); using (IDataReader reader = db.ExecuteReader(cmd)) { if (reader.Read()) { student = new Student() { Id = reader.GetInt32(0), ClassId = reader.GetInt32(1), Sid = reader.GetString(2), Password = reader.GetString(3), Name = reader.GetString(4), Sex = reader.GetInt32(5), Birthday = reader.GetDateTime(6), IsAdmin = reader.GetInt32(7) }; } } return student; } /// <summary> /// 查询所有学生信息 /// </summary> /// <returns></returns> public IList<Student> SelectAll() { List<Student> list = new List<Student>(); Database db = DBHelper.CreateDataBase(); StringBuilder sb = new StringBuilder(); sb.Append("select * from Student "); DbCommand cmd = db.GetSqlStringCommand(sb.ToString()); using (IDataReader reader = db.ExecuteReader(cmd)) { while (reader.Read()) { list.Add(new Student() { Id = reader.GetInt32(0), ClassId = reader.GetInt32(1), Sid = reader.GetString(2), Password = reader.GetString(3), Name = reader.GetString(4), Sex = reader.GetInt32(5), Birthday = reader.GetDateTime(6), IsAdmin = reader.GetInt32(7) }); } } return list; } /// <summary> /// 查询所有学生信息 /// </summary> /// <returns></returns> public IList<Student> SelectAllMapper() { var list = new List<Student>(); Database db = DBHelper.CreateDataBase(); DataAccessor<Student> studentAccessor; //studentAccessor = db.CreateSqlStringAccessor("select * from Student", // MapBuilder<Student>.MapAllProperties(). // Build() // ); studentAccessor = db.CreateSqlStringAccessor("select * from Student", MapBuilder<Student>.MapAllProperties(). Map(p => p.Id).ToColumn("ID"). Map(p => p.Sid).ToColumn("SID"). Map(p => p.Password).WithFunc(f => "******").//将密码转换为"*",无法直接查看 Map(p => p.Name).WithFunc(ToUpperName).//将学员名称转换为大写 Map(p => p.Sex).ToColumn("Sex"). Map(p => p.Birthday).ToColumn("Birthday"). Build() ); list = studentAccessor.Execute().ToList(); return list; } /// <summary> /// 将学员名称转换为大写 /// </summary> /// <param name="dataRecord"></param> /// <returns></returns> private string ToUpperName(IDataRecord dataRecord) { var name = (string)dataRecord["Name"]; return name.ToUpper(); } public Student SelectBySid(string sid) { Student student = null; Database db = DBHelper.CreateDataBase(); StringBuilder sb = new StringBuilder(); sb.Append("select * from Student "); sb.Append(" where SID=@SID"); DbCommand cmd = db.GetSqlStringCommand(sb.ToString()); db.AddInParameter(cmd, "@SID", DbType.String, sid); using (IDataReader reader = db.ExecuteReader(cmd)) { if (reader.Read()) { student = new Student() { Id = reader.GetInt32(0), ClassId = reader.GetInt32(1), Sid = reader.GetString(2), Password = reader.GetString(3), Name = reader.GetString(4), Sex = reader.GetInt32(5), Birthday = reader.GetDateTime(6), IsAdmin = reader.GetInt32(7) }; } } return student; } } }
其中的代码都是采用了比较常见的老套路:
1、获取数据库对象
2、构建Command对象并进行执行语句及参数赋值
3、通过数据库对象调用相应方法执行Command
企业库在Data Access上帮我们做了比较好的封装,相当于为我们提供了如SQLHelper,OracleHelper类,只不过这个帮助类转换了一个个数据库的对象,通过数据库对象来对数据库数据进行操作
(个人认为通过这种方式进行操作更加直观,而且企业库的对SQL语句的参数操作方法也很直观:AddInParameter,AddOutParameter,GetParameterValue很好的区分了参数的操作,比原来的SQLCommand好多了)
如果仔细看了上面操作代码的朋友肯定发现了类中有个叫SelectAllMapper的方法,这个方法采用的是企业库5.0中新提供的Accessor进行RowMapper来直接为实体赋值,相比原来的使用reader方式取值赋值更加优雅, 只要SQL查询出来的对象字段和实体对象属性一样就可以使用MapAllProperties()方法直接赋值,如果不同的话可以使用map方法来对个别 属性单独映射,而且在映射的时候还可以使用WithFunc来进行进一步操作,在代码中我将密码进行了替换,以“*”的形式展示,同时把学员的名称以大写 的形式展示。
(注:更多的企业库Data Access模块方法使用可以点击这里下载微软给出的学习例子和http://www.entlib.com/发布的学习手册)
在完成底层的操作,现在我们就开始对企业库的数据库访问进行配置:
在Web层的Web.config上右键打开企业库配置器:Blocks-Add Data Settings-Add DataBase Connstring,新建2个数据库对象,一个是MS SqlServer数据库,一个是SQLite数据库.
新建一个数据库设置
新建二个数据库连接
一个为EntLibStudy,另一个为EntLibSQLite
我们来看下具体的配置文件代码:
<configuration> <configSections> <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" /> </configSections> <dataConfiguration defaultDatabase="EntLibStudy" /> <connectionStrings> <add name="EntLibStudy" connectionString="server=VOLK\SQL2005;database=EntLibStudy;Integrated Security=True;" providerName="System.Data.SqlClient" /> <add name="EntLibStudySQLite" connectionString="data source=|DataDirectory|EntLibStudySQLite.db3" providerName="System.Data.SQLite" /> </connectionStrings> <appSettings> <add key="DAL" value="EntLibStudy.DAL" /> </appSettings> <system.web> <compilation debug="true" targetFramework="4.0" > <expressionBuilders> <add expressionPrefix="RouteUrl" type="System.Web.Compilation.RouteUrlExpressionBuilder"/> <add expressionPrefix="RouteValue" type="System.Web.Compilation.RouteValueExpressionBuilder"/> </expressionBuilders> </compilation> <authentication mode="Forms"> </authentication> </system.web> </configuration>
至此我们就完成了Data Access模块的代码编写和基本设置(具体代码请到文章底部下载源代码,类似代码则不再描述)。
这时如果项目需求发生了变更,由于成本太高不能使用MS SQL SERVER,而要改用SQLite数据库时则只需更改配置文件,将dataConfiguration配置节中defaultDatabase更改为EntLibStudySQLite,将appSettings配置节中DAL的值改为EntLibStudy.DALSQLite即可立刻切换到SQLite数据库。
下面我来看下运行出来的效果:
红色框中地址采用了ASP.NET4中的路由功能,实现了地址重写
红框中如上面的分析,在DAL层进行属性映射的时候已经将密码以*代替,学员姓名以大写形式展现(此页面仅用来展示属性映射,无其他用处,页面地址为:~/Student/StudentList.aspx)
至此,学习之路的第二步——Data Access模块的学习就到此为止了,其他一些东西请下载源代码查看。
注意:
1、MSSQL数据库在DataBase目录下(需要自行附加数据库),SQLite数据库在Web目录的App_Data下,由于考虑到项目的大小,所以每个项目的BIN目录都已经删除,如出现无法生成项目请自行添加相关企业库的DLL。
2、由于微软企业库5.0 学习之路这个系列我是准备以一个小型项目的形式介绍企业库的各模块,所以源代码会根据系列文章的更新而更新,所以源代码不能保证与文章中所贴代码相同。
3、项目开发环境为:VS2010+SQL2005。
4、管理员帐户:admin
密码:admin
项目下载地址:点我下载