NHibernate框架与BLL+DAL+Model+Controller+UI 多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

时间:2021-05-01 11:05:57

原文://http://blog.csdn.net/wb09100310/article/details/47271555

1. 概述

搭建了Spring.NET+NHibernate的一个数据查询系统。之前没用过这两个框架,也算是先学现买,在做完设计之 后花了一周搭建成功了。其中,还加上了我的一些改进思想,把DAO和BLL之中相似且常用的增删改查通过泛型T抽象到了DAO和BLL的父类中,其DAO 和BLL子类只需继承父类就拥有了这些方法。和之前的一个数据库表(视图)对应一个实体,一个实体对应一个DAO和一个BLL,而每一个DAO和BLL都 是相似的增删改查相比,减少了大量代码量。现在就对这些知识做一个总结,方便自己学习,同时把自己的所思所悟分享给大家,不足知足望大家指点迷津!

2. 知识准备

温馨提示,学习本系列知识,须至少具备如下知识。否则请移步,熟悉下列知识之后再回来学习:

1.C#基础扎实,熟悉泛型、反射、linq(最好有所了解)、ADO.NET

2.熟悉XML

3.对控制反转(IOC)、依赖注入(DI),Spring.net等理论知识有所了解,可以参考如下博文:

Spring.NET学习笔记:http://www.cnblogs.com/GoodHelper/archive/2009/11/20/SpringNet_Index.html

SPRING.NET 1.3.2学习:http://blog.csdn.net/lee576/article/category/1353489/2

4.对Nhibernate理论知识有所了解,参考资料

NHibernate之旅:http://www.cnblogs.com/lyj/archive/2008/10/10/1308267.html

Nhibernate从入门到精通:http://www.cnblogs.com/GoodHelper/archive/2011/02/14/nhiberante_01.html

5.Spring.NET+Nhibernate参考资料:

Spring.NET学习笔记18——整合NHibernate(基础篇)Level 300:http://www.cnblogs.com/GoodHelper/archive/2009/11/18/SpringNet_NHibernate.html

Spring.NET 1.3.2 集成 NHibernate 3.2:http://www.cnblogs.com/haogj/archive/2012/07/28/nhibernate.html

3.项目介绍

本项目后端采用Spring.NET2.0+Nhibernate4.0的经典三层架构,web端采用的是ASP.NET(本来打算用MVC,考虑到项目组成员对web开发不熟),项目结构如下:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

说明:

Model:实体层,在NHibernate中也叫持久层

IDAO:数据库访问层接口

NHibernateDAO:实现IDAO,NHibernate框架实现数据库访问层

IBLL:业务逻辑接口层

BLL:业务逻辑层

Common:工具类库层

WebUI:表现层,ASP.NET,采用了BootStrap框架。这一层不是本次学习的重点

4.Spring.NET简单介绍

Spring.NET是一个应用程序框架,其目的是协助开发人员创建企业级的.NET应用程序。它提供了很多方面的功能,比如依赖注入、面向方面编程(AOP)、数据访问抽象及ASP.NET扩展等等。Spring.NET以Java版的Spring框架为基础,将Spring.Java的核心概念与思想移植到了.NET平台上。

Spring.NET的IOC容器所解决的,正是如何在企业应用中将类、对象和服务组合成应用程序的问题。IOC容器通过很正统(按:formalized,言下之意是这些方式都是已经定型了的、经过了业界多年考验的)的方式将分散的组件组合成完整的应用程序。Spring.NET框架所采用的,都是被业界无数应用程序考验多年的、已经被定型为设计模式的最佳编程方式,实际上,这些模式已经成为我们架构和开发时的法典,而通过Spring.NET,我们可以直接将它们整合到自己的应用程序中。目前已有很多组织和机构用Spring框架开发出了强壮的、维护性好的应用程序,这确实是一件非常好的事情。

Spring.NET框架包含了许多功能方面,它们都进入如下图所示的模块组织。下图显示了Spring.NET各核心模块:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

Spring.Core作为整个框架的基础, ,实现了依赖注入的功能。

Spring.AOP为业务对象提供面向方面编程(AOP)的支持。

Spring.Data定义了一个抽象的数据访问层,可以跨越各种数据访问技术(从ADO.NET到各种ORM)进行数据访问。

Spring.Data.NHibernate使用此模块集成到Spring的声明式事务管理功能NHibernate的能容易地操作ADO.NET和NHibernate的混合在同一事务。

5.NHibernate框架简单介绍

NHibernate是一个面向.NET环境的对象/关系数据库映射工具。对象关系映射(O/R
Mapping,Object Relational Mapping)表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。

NHibernate不仅仅管理.NET类到数据库表的映射(包括.NET数据类型到SQL数据类型的映射),还提供数据查询和获取数据的方法,大幅度减少我们开发时人工使用SQL和ADO.NET处理数据的时间。NHibernate的目标是对于开发者通常的数据持久化相关的编程任务,解放其中的95%。并请记住NHibernate作为数据库访问层,是与你的程序紧密集成的。不过我个人觉得:NHibernate的性能明显没有纯sql性能好,不过在不太多考虑性能的情况下,它是比较好的选择!

按照搭建项目的顺序来比较好描述一些,我一般先搭建实体层,本节内容纯属于NHibernate范畴。先上图和代码,然后对着图和代码逐一讲解,以角色表为例:

『Spring.NET+NHibernate+泛型』框架搭建之Model(二)

  T_Role表:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

数据库表设计很简单,ID为主键,并且是自增长的,其他字段还包括角色名称(Name)、描述(Content)、排序(Sort)、状态(Status)、Del(是否删除)。这里就不对T_Role表赘述了。

   T_Role类:

  1. using System;
  2. //Nhibernate Code Generation Template 1.0
  3. //author:MythXin
  4. //blog:www.cnblogs.com/MythXin
  5. //Entity Code Generation Template
  6. namespace Model{
  7. //T_Role
  8. public class T_Role
  9. {
  10. /// <summary>
  11. /// ID
  12. /// </summary>
  13. public virtual int ID
  14. {
  15. get;
  16. set;
  17. }
  18. /// <summary>
  19. /// Name
  20. /// </summary>
  21. public virtual string Name
  22. {
  23. get;
  24. set;
  25. }
  26. /// <summary>
  27. /// Content
  28. /// </summary>
  29. public virtual string Content
  30. {
  31. get;
  32. set;
  33. }
  34. /// <summary>
  35. /// Order
  36. /// </summary>
  37. public virtual int? Sort
  38. {
  39. get;
  40. set;
  41. }
  42. /// <summary>
  43. /// 1 启用(默认)
  44. ///0 禁用
  45. /// </summary>
  46. public virtual string Status
  47. {
  48. get;
  49. set;
  50. }
  51. /// <summary>
  52. /// 1 正常(默认)
  53. ///0 删除
  54. /// </summary>
  55. public virtual string Del
  56. {
  57. get;
  58. set;
  59. }
  60. }
  61. }

T_Role类必须与T_Role表的字段一一对应,名字可以不一样,但是字段属性数量和类型必须是一一对应的,此外,每个字段属性都必须为virtual的。

T_Role表与T_Role的映射文件:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Model" >
  3. <class name="Model.T_Role, Model" table="T_Role">
  4. <id name="ID" column="ID" type="int" unsaved-value="0">
  5. <generator class="native"/>
  6. </id>
  7. <property name="Name" type="string" column="Name" />
  8. <property name="Content" type="string" column="Content" />
  9. <property name="Sort" type="int" column="Sort" />
  10. <property name="Status" type="string" column="Status" />
  11. <property name="Del" type="string" column="Del" />
  12. </class>
  13. </hibernate-mapping>

顾名思义,T_Role的映射文件是映射T_Role类和T_Role表的。注意以下几点:

(1) 必须按照上述格式书写,其中:

a. hibernate-mapping固定上述格式,assembly为文件所在的命名空间;

b. class标签中的name为“T_Role的命名空间.T_Role,T_Role的命名空间”,table为T_Role表的表名;

c. id标签为主键,必须有主键,unsaved-value="0"意思是默认值是0,<generator class="native"/>表示按照数据库定义的方式处理主键,如我定义了自增长;

d. id或property标签中的name为T_Role类中字段名称,而column必须为与之对应的T_Role表的字段名称,且数据类型相同;

(2) 文件必须以.hbm.xml后缀结尾,如:T_Role.hbm.xml;

(3) 必须右键点击文件-属性,将生成操作选为“嵌入的资源

说明:T_Role类文
件(.cs文件)和T_Role映射文件(.hbm.xml)按理说可以分别放到不同的文件夹,但是这样放,运行的时候却提示找不到,最后无奈只能放一起
了。要是哪位大神解决了此问题麻烦留言告知,谢谢。另外,视图和表的方式完全一样的,映射的时候指定映射的视图就行了。

最后,实体类和映射文件都是可以通过代码生成器生成的,建议不要自己去写,容易出错,还找不出错在哪里,用代码生成器生成之后不对的修改下就可以了。我使
用的动软代码生成器,代码生成器连接上数据库后,右键对应的数据库选择“模板代码批量生成”,选定要生成的表、模板就可以了,操作很简单,就不详述了,不
清楚的留言,或加入博客签名里的QQ群交流。

贴上Model的目录图,并不需要任何多余的引用:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

『Spring.NET+NHibernate+泛型』框架搭建之DAO(三)★

本节内容介绍Nhibernate所封装的数据库访问层。不过我加入了泛型进行封装。大概思路:首先,我们有一个接口层,还有一个对应的实现层;在接口层 中我们先定义一个父接口,父接口中定义每一个接口都可能会用到的方法,然后其他接口继承此父接口即可。如果子接口需要使用特殊的方法,可以单独定义在子接 口中;在接口实现层中也是类似的,定义一个父类,里面写好实现了接口层父接口的方法,其他实现层同样继承父接口和实现层父类,接口层中定义的特殊方法也在 对应的实现类中进行实现。这样做可以有效的把相似的重复代码(重复的增删改查)尽可能的减少,并且这样设计比较灵活,重复的写一次就行了,特殊的单独写, 维护起来也比较方便。这样描述可能不是很明白,下面详细介绍实现步骤。

一、数据库访问接口层IDAO

1. 在解决方案上右键新建一个类库,命名为IDAO,用来存放Nhibernae数据库访问接口层代码,并添加引用上一节所讲的实体层Model;

2. 在类库中添加一个父接口,命名为IDAO,并定义常用的方法,代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace IDAO
  6. {
  7. public interface IDAO<T>
  8. {
  9. /// <summary>
  10. /// 添加实体
  11. /// </summary>
  12. /// <param name="entity"></param>
  13. int Add(T entity);
  14. /// <summary>
  15. /// 修改实体
  16. /// </summary>
  17. /// <param name="entity"></param>
  18. void Update(T entity);
  19. /// <summary>
  20. /// 保存或修改实体
  21. /// </summary>
  22. /// <param name="customer"></param>
  23. void SaveOrUpdate(IList<T> list);
  24. /// <summary>
  25. /// 删除实体
  26. /// </summary>
  27. /// <param name="entity"></param>
  28. void Delete(T entity);
  29. /// <summary>
  30. /// 按条件删除
  31. /// </summary>
  32. /// <param name="sqlWhere">删除条件</param>
  33. void Delete(string sqlWhere);
  34. /// <summary>
  35. /// 根据ID得到实体
  36. /// </summary>
  37. /// <param name="id"></param>
  38. /// <returns></returns>
  39. T Get(int id);
  40. /// <summary>
  41. /// 根据ID得到实体
  42. /// </summary>
  43. /// <param name="id"></param>
  44. /// <returns></returns>
  45. T Load(int id);
  46. /// <summary>
  47. /// 得到所有实体
  48. /// </summary>
  49. /// <returns></returns>
  50. IList<T> LoadAll();
  51. /// <summary>
  52. /// 按条件排序得到前N条记录
  53. /// </summary>
  54. /// <param name="top">获取条数</param>
  55. /// <param name="field">排序字段</param>
  56. /// <param order="field">排序方式,升序asc,降序desc</param>
  57. /// <returns></returns>
  58. IList<T> QueryTop(int top, string field, string order);
  59. /// <summary>
  60. /// 根据条件得到实体
  61. /// </summary>
  62. /// <param name="sqlWhere">查询条件</param>
  63. /// <returns></returns>
  64. IList<T> Where(string sqlWhere);
  65. /// <summary>
  66. /// 得到统计数量
  67. /// </summary>
  68. /// <param name="strWhere">查询条件</param>
  69. /// <returns></returns>
  70. int GetRecordCount(string strWhere);
  71. /// <summary>
  72. /// 分页获取数据列表
  73. /// </summary>
  74. /// <param name="PageSize">每页获取数据条数</param>
  75. /// <param name="PageIndex">当前页是第几页</param>
  76. /// <param name="strWhere">查询条件</param>
  77. /// <returns></returns>
  78. IList<T> GetPageList(int PageSize, int PageIndex, string strWhere);
  79. /// <summary>
  80. /// 根据数据字典父编码和编码获取名称
  81. /// </summary>
  82. /// <param name="parentNumber">父编码</param>
  83. /// <param name="number">编码</param>
  84. /// <returns></returns>
  85. string GetName(string parentNumber, string number);
  86. /// <summary>
  87. /// 获取该父编码下最大编码
  88. /// </summary>
  89. /// <param name="parentNumber">父编码</param>
  90. /// <returns></returns>
  91. int GetMaxNumber(string parentNumber);
  92. }
  93. }

3.定义好了父接口,下面定义子接口,还是以IT_RoleDAO为例,代码如下:

  1. using System;
  2. using Model;
  3. namespace IDAO
  4. {
  5. public interface IT_RoleDAO : IDAO<T_Role>
  6. {
  7. }
  8. }

这样,IT_RoleDAO就拥有了IDAO定义了的方法,如果IT_RoleDAO有特殊方法,直接添加在IT_RoleDAO里面即可,以IT_AreaDAO为例,代码如下:

  1. using System;
  2. using Model;
  3. namespace IDAO
  4. {
  5. public interface IT_AreaDAO : IDAO<T_Area>
  6. {
  7. /// <summary>
  8. /// 获取
  9. /// </summary>
  10. /// <param name="parentNumber"></param>
  11. /// <returns></returns>
  12. int GenerateAreaNumber(string parentNumber);
  13. }
  14. }

最后,我们看一下IDAO层的文件目录:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

二、NHibernate数据库访问实现层NHibernateDAO(核心)

1. 在解决方案上右键新建一个类库,命名为NHibernateDAO,用来存放Nhibernae数据库访问实现层代码,并添加引用上一节所讲的实体层Model和接口层IDAO;

2. 右键点击引用,选择“管理NuGet程序包”,选择“联机”,搜索
“Spring.NET”,在搜索结果中选择“Spring.Net NHibernate 4
support”安装。该安装包括了一个NHibernate,但是还不够,同样的方法搜索NHibernate,并安装,添加Nhibernate就不上图了,添加Spring.NET的界面图如下:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

3.添加数据库访问层父类NHibernateDAO,NHibernateDAO类中的SessionFactory属性的
GetCurrentSession方法可以实例化ISession,实例化ISession后的对象可以调用NHibernate下的数据库操作方法,
具体他们之间怎么实例化,先上代码,后面再来解释。

NHibernateDAO代码如下,继承INHibernateSessionFactory和实现IDAO父接口:

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using Model;
  6. using IDAO;
  7. using NHibernate;
  8. using NHibernate.Criterion;
  9. using NHibernate.Linq;
  10. using Spring.Data.NHibernate.Support;
  11. using NHibernate.Cfg;
  12. using System.Text;
  13. namespace NHibernateDAO
  14. {
  15. [Spring.Stereotype.Repository]
  16. public class NHibernateDAO<T> : IDAO<T>
  17. {
  18. public ISessionFactory SessionFactory { get; set; }
  19. /// <summary>
  20. /// 获取Session
  21. /// </summary>
  22. public ISession Session
  23. {
  24. get
  25. {
  26. return SessionFactory.GetCurrentSession();
  27. }
  28. }
  29. /// <summary>
  30. /// 当前实体对应的表名
  31. /// </summary>
  32. public string TableName
  33. {
  34. get { return typeof(T).ToString().Substring(typeof(T).ToString().LastIndexOf('.') + 1); }
  35. }
  36. /// <summary>
  37. /// 添加实体
  38. /// </summary>
  39. /// <param name="entity"></param>
  40. public int Add(T entity)
  41. {
  42. using (ITransaction transaction = Session.BeginTransaction())
  43. {
  44. try
  45. {
  46. int id = (int)Session.Save(entity);
  47. Session.Flush();
  48. transaction.Commit();
  49. return id;
  50. }
  51. catch (HibernateException)
  52. {
  53. transaction.Rollback();
  54. throw;
  55. }
  56. }
  57. }
  58. /// <summary>
  59. /// 修改实体
  60. /// </summary>
  61. /// <param name="entity"></param>
  62. public void Update(T entity)
  63. {
  64. using (ITransaction transaction = Session.BeginTransaction())
  65. {
  66. try
  67. {
  68. Session.Update(entity);
  69. Session.Flush();
  70. transaction.Commit();
  71. }
  72. catch (HibernateException)
  73. {
  74. transaction.Rollback();
  75. throw;
  76. }
  77. }
  78. }
  79. /// <summary>
  80. /// 保存或修改实体
  81. /// </summary>
  82. /// <param name="customer"></param>
  83. public void SaveOrUpdate(IList<T> list)
  84. {
  85. using (ITransaction transaction = Session.BeginTransaction())
  86. {
  87. try
  88. {
  89. foreach (var entity in list)
  90. {
  91. Session.SaveOrUpdate(entity);
  92. }
  93. Session.Flush();
  94. transaction.Commit();
  95. }
  96. catch (HibernateException)
  97. {
  98. transaction.Rollback();
  99. throw;
  100. }
  101. }
  102. }
  103. /// <summary>
  104. /// 删除实体
  105. /// </summary>
  106. /// <param name="entity"></param>
  107. public void Delete(T entity)
  108. {
  109. using (ITransaction transaction = Session.BeginTransaction())
  110. {
  111. try
  112. {
  113. Session.Delete(entity);
  114. Session.Flush();
  115. transaction.Commit();
  116. }
  117. catch (HibernateException)
  118. {
  119. transaction.Rollback();
  120. throw;
  121. }
  122. }
  123. }
  124. /// <summary>
  125. /// 按条件删除
  126. /// </summary>
  127. /// <param name="sqlWhere">删除条件</param>
  128. public void Delete(string sqlWhere)
  129. {
  130. using (ITransaction transaction = Session.BeginTransaction())
  131. {
  132. try
  133. {
  134. Session.Delete(string.Format("from {0} Where {1}", TableName, sqlWhere));
  135. Session.Flush();
  136. transaction.Commit();
  137. }
  138. catch (HibernateException)
  139. {
  140. transaction.Rollback();
  141. throw;
  142. }
  143. }
  144. }
  145. /// <summary>
  146. /// 根据ID得到实体
  147. /// </summary>
  148. /// <param name="id"></param>
  149. /// <returns></returns>
  150. public T Get(int id)
  151. {
  152. return Session.Get<T>(id);
  153. }
  154. /// <summary>
  155. /// 根据ID得到实体
  156. /// </summary>
  157. /// <param name="id"></param>
  158. /// <returns></returns>
  159. public T Load(int id)
  160. {
  161. return Session.Load<T>(id);
  162. }
  163. /// <summary>
  164. /// 得到所有实体
  165. /// </summary>
  166. /// <returns></returns>
  167. public IList<T> LoadAll()
  168. {
  169. return Session.Query<T>().ToList();
  170. }
  171. /// <summary>
  172. /// 按条件排序得到前N条记录
  173. /// </summary>
  174. /// <param name="top">获取条数</param>
  175. /// <param name="field">排序字段</param>
  176. /// <param order="field">排序方式,升序asc,降序desc</param>
  177. /// <returns></returns>
  178. public IList<T> QueryTop(int top, string field, string order)
  179. {
  180. if (order == "asc")
  181. {
  182. return Session.CreateCriteria(typeof(T)).SetMaxResults(top).AddOrder(Order.Asc(field)).List<T>();
  183. }
  184. else
  185. {
  186. return Session.CreateCriteria(typeof(T)).SetMaxResults(top).AddOrder(Order.Desc(field)).List<T>();
  187. }
  188. }
  189. /// <summary>
  190. /// 根据条件得到实体
  191. /// </summary>
  192. /// <param name="sqlWhere">查询条件</param>
  193. /// <returns></returns>
  194. public IList<T> Where(string sqlWhere)
  195. {
  196. StringBuilder strSql = new StringBuilder(string.Format("from {0} c", TableName));
  197. if (!string.IsNullOrEmpty(sqlWhere))
  198. {
  199. strSql.Append(string.Format(" where {0}", sqlWhere));
  200. }
  201. return Session.CreateQuery(strSql.ToString()).List<T>();
  202. }
  203. /// <summary>
  204. /// 得到统计数量
  205. /// </summary>
  206. /// <param name="strWhere">查询条件</param>
  207. /// <returns></returns>
  208. public int GetRecordCount(string sqlWhere)
  209. {
  210. StringBuilder strSql = new StringBuilder(string.Format("select count(1) from {0} c", TableName));
  211. if (!string.IsNullOrEmpty(sqlWhere))
  212. {
  213. strSql.Append(string.Format(" where {0}", sqlWhere));
  214. }
  215. return (int)Session.CreateSQLQuery(strSql.ToString()).UniqueResult();
  216. }
  217. /// <summary>
  218. /// 分页获取数据列表
  219. /// </summary>
  220. /// <param name="PageSize">每页获取数据条数</param>
  221. /// <param name="PageIndex">当前页是第几页</param>
  222. /// <param name="strWhere">查询条件</param>
  223. /// <returns></returns>
  224. public IList<T> GetPageList(int PageSize, int PageIndex, string sqlWhere)
  225. {
  226. StringBuilder strSql = new StringBuilder();
  227. strSql.Append(string.Format("select top {0} * from {1} where ID not in(select top  ", PageSize,
  228. TableName));
  229. strSql.Append(PageSize * (PageIndex - 1));
  230. strSql.Append(string.Format(" ID from {0}", TableName));
  231. if (!string.IsNullOrEmpty(sqlWhere))
  232. {
  233. strSql.Append(string.Format(" where {0} ) and {0}", sqlWhere));
  234. }
  235. else
  236. {
  237. strSql.Append(")");
  238. }
  239. return Session.CreateSQLQuery(strSql.ToString()).AddEntity(typeof(T)).List<T>();
  240. }
  241. /// <summary>
  242. /// 根据数据字典父编码和编码获取名称
  243. /// </summary>
  244. /// <param name="parentNumber">父编码</param>
  245. /// <param name="number">编码</param>
  246. /// <returns></returns>
  247. public string GetName(string parentNumber, string number)
  248. {
  249. string[] num = number.Split(',');
  250. List<string> list = new List<string>();
  251. list.AddRange(num);
  252. IQueryable<string> name = from q in Session.Query<T_Dictionary>()
  253. where q.ParentNumber == parentNumber && list.Contains(q.Number)   orderby q.Number
  254. select q.Name;
  255. string nameStr = "";
  256. foreach (string n in name)
  257. {
  258. nameStr += n + ",";
  259. }
  260. return nameStr.Contains(",") ? nameStr.Substring(0, nameStr.Length - 1) : nameStr;
  261. }
  262. /// <summary>
  263. /// 获取该父编码下最大编码
  264. /// </summary>
  265. /// <param name="parentNumber">父编码</param>
  266. /// <returns></returns>
  267. public int GetMaxNumber(string parentNumber)
  268. {
  269. string strSql =
  270. string.Format(
  271. "select case when MAX(cast(substring(Number,len(Number)-3,4) as int)) is null then 0 else MAX(cast(substring(Number,len(Number)-3,4) as int)) end  from {0} where ParentNumber='{1}'",
  272. TableName, parentNumber);
  273. return ++Session.CreateQuery(strSql).List<int>()[0];
  274. }
  275. }
  276. }

4. 添加一个数据库访问层实现类,以T_RoleDAO为例:

  1. using System;
  2. using System.Collections;
  3. using IDAO;
  4. using Model;
  5. namespace NHibernateDAO
  6. {
  7. public class T_RoleDAO : NHibernateDAO<T_Role>, IT_RoleDAO
  8. {
  9. }
  10. }

同样滴,继承NHibernateDAO并实现IT_RoleDAO接口,他便拥有了他们定义好的方法。如果有特殊方法代码如下:

  1. using System;
  2. using System.Collections;
  3. using Model;
  4. using IDAO;
  5. using System.Text;
  6. using System.Collections.Generic;
  7. using NHibernate;
  8. namespace NHibernateDAO
  9. {
  10. public class T_AreaDAO : NHibernateDAO<T_Area>,IT_AreaDAO
  11. {
  12. public int GenerateAreaNumber(string parentNumber)
  13. {
  14. string sqlStr = string.Format(@"select case when MAX(cast(Number as int)) is null  then 0
  15. else MAX(cast(Number as int)) end
  16. from {0}
  17. where ParentNumber={1}", TableName, parentNumber);
  18. return ++Session.CreateQuery(sqlStr).List<int>()[0];
  19. }
  20. }
  21. }

5.
下面,就来解释一下他们都是怎么实例化的。这里就用到Spring.NET依赖注入的方式实现,先看配置文件。在NHibernateDAO类库下添加文
件夹Config,用来存放配置文件,然后添加一个命名为objects.xml的xml。这里必须定义每一个数据库访问层对象,不能说他们都继承
NHibernateDAO,只定义NHibernateDAO,这样的话会报错,因为后面BLL层要调用DAO层,他们之间是一一对应的,这里先简单提
一下,后面讲到就明白了。代码如下:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <objects xmlns="http://www.springframework.net">
  3. <!--T_AreaDAO,管理T_Area的对象-->
  4. <object id="T_AreaDAO" type="NHibernateDAO.T_AreaDAO,NHibernateDAO">
  5. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  6. </object>
  7. <!--T_AssessmentCoefficientDAO,管理T_AssessmentCoefficient的对象-->
  8. <object id="T_AssessmentCoefficientDAO" type="NHibernateDAO.T_AssessmentCoefficientDAO,NHibernateDAO">
  9. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  10. </object>
  11. <!--T_AuthorityDAO,管理T_Authority的对象-->
  12. <object id="T_AuthorityDAO" type="NHibernateDAO.T_AuthorityDAO,NHibernateDAO">
  13. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  14. </object>
  15. <!--T_ClientDAO,管理T_Client的对象-->
  16. <object id="T_ClientDAO" type="NHibernateDAO.T_ClientDAO,NHibernateDAO">
  17. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  18. </object>
  19. <!--T_DictionaryDAO,管理T_Dictionary的对象-->
  20. <object id="T_DictionaryDAO" type="NHibernateDAO.T_DictionaryDAO,NHibernateDAO">
  21. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  22. </object>
  23. <!--T_DrugDAO,管理T_Drug的对象-->
  24. <object id="T_DrugDAO" type="NHibernateDAO.T_DrugDAO,NHibernateDAO">
  25. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  26. </object>
  27. <!--T_InvoicingCollectDetailDAO,管理T_InvoicingCollectDetail的对象-->
  28. <object id="T_InvoicingCollectDetailDAO" type="NHibernateDAO.T_InvoicingCollectDetailDAO,NHibernateDAO">
  29. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  30. </object>
  31. <!--T_InvoicingDetailDAO,管理T_InvoicingDetail的对象-->
  32. <object id="T_InvoicingDetailDAO" type="NHibernateDAO.T_InvoicingDetailDAO,NHibernateDAO">
  33. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  34. </object>
  35. <!--T_LogDAO,管理T_Log的对象-->
  36. <object id="T_LogDAO" type="NHibernateDAO.T_LogDAO,NHibernateDAO">
  37. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  38. </object>
  39. <!--T_MenuDAO,管理T_Menu的对象-->
  40. <object id="T_MenuDAO" type="NHibernateDAO.T_MenuDAO,NHibernateDAO">
  41. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  42. </object>
  43. <!--T_OpHistoryDAO,管理T_OpHistory的对象-->
  44. <object id="T_OpHistoryDAO" type="NHibernateDAO.T_OpHistoryDAO,NHibernateDAO">
  45. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  46. </object>
  47. <!--T_RoleDAO,管理T_Role的对象-->
  48. <object id="T_RoleDAO" type="NHibernateDAO.T_RoleDAO,NHibernateDAO">
  49. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  50. </object>
  51. <!--T_UserDAO,管理T_User的对象-->
  52. <object id="T_UserDAO" type="NHibernateDAO.T_UserDAO,NHibernateDAO">
  53. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  54. </object>
  55. <!--V_InvoicingCollectDetailDAO,管理V_InvoicingCollectDetail的对象-->
  56. <object id="V_InvoicingCollectDetailDAO" type="NHibernateDAO.V_InvoicingCollectDetailDAO,NHibernateDAO">
  57. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  58. </object>
  59. <!--V_InvoicingDetailDAO,管理V_InvoicingDetail的对象-->
  60. <object id="V_InvoicingDetailDAO" type="NHibernateDAO.V_InvoicingDetailDAO,NHibernateDAO">
  61. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  62. </object>
  63. <!--V_TrackDAO,管理V_Track的对象-->
  64. <object id="V_TrackDAO" type="NHibernateDAO.V_TrackDAO,NHibernateDAO">
  65. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  66. </object>
  67. <!--V_CoverageRateDAO,管理V_CoverageRate的对象-->
  68. <object id="V_CoverageRateDAO" type="NHibernateDAO.V_CoverageRateDAO,NHibernateDAO">
  69. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  70. </object>
  71. <!--V_AssessDAO,管理V_Assess的对象-->
  72. <object id="V_AssessDAO" type="NHibernateDAO.V_AssessDAO,NHibernateDAO">
  73. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  74. </object>
  75. <!--T_BuyDetailDAO,管理T_BuyDetail的对象-->
  76. <object id="T_BuyDetailDAO" type="NHibernateDAO.T_BuyDetailDAO,NHibernateDAO">
  77. <property name="SessionFactory" ref="NHibernateSessionFactory"/>
  78. </object>
  79. </objects>

格式如上述代码,先定义一个objects根节点,然后再objects中定义每一
个数据库访层,type指定“命名空间.类名,命名空间”,property指定属性,name必须与NHibernateDAO中的
SessionFactory相同,由于每一个数据库访问层都继承了NHibernateDAO,所有他们就拥有了NHibernateDAO的属性
SessionFactory,ref指定SessionFactory实例化的对象,NHibernateSessionFactory是
NHibernate框架封装的数据库访问类。所以,我们看到我们没有在代码中实实例化SessionFactory,只是定义了一个属性,而是通过Spring.NET的配置文件来把SessionFactory实例化的,这就是所谓的依赖注入,也交控制反转。

6. 细心的撸友可以发现了,数据库操作的类和方法我们定义好了,但是数据访问的连接字符串还没有,下面就来配置数据库访问文件。同样在NHibernateDAO的Config中添加DataAccess.xml,代码如下:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <objects xmlns="http://www.springframework.net"
  3. xmlns:db="http://www.springframework.net/database"
  4. xmlns:tx="http://www.springframework.net/tx"
  5. >
  6. <!--描述-->
  7. <description>
  8. 数据访问的配置信息
  9. 包括:DbProvider
  10. NHibernate
  11. </description>
  12. <!-- 通过主应用程序的上下文配置文件引用 -->
  13. <object type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
  14. <property name="ConfigSections" value="spring/databaseSettings"/>
  15. </object>
  16. <!-- 数据库的配置 -->
  17. <db:provider id="DbProvider"
  18. provider="SqlServer-2.0"
  19. connectionString="Data Source=${db.server};Database=${db.database};User ID=${db.userid} ;PassWord=${db.password}"
  20. />
  21. <!-- NHibernate 配置 -->
  22. <!-- 可以通过 name 为其指定别名 name="SessionFactory" -->
  23. <object id="NHibernateSessionFactory"
  24. type="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate4"
  25. >
  26. <!-- 关于数据库连接的配置,直接使用 DbProvider 中的设置,这样,不需要为 Hibernate 再提供连接串和驱动 -->
  27. <property name="DbProvider" ref="DbProvider"/>
  28. <!-- 包含有映射文件的程序集,需要分析的hbm程序集名称 -->
  29. <property name="MappingAssemblies">
  30. <list>
  31. <value>Model</value>
  32. </list>
  33. </property>
  34. <!-- 其他的参数 -->
  35. <property name="HibernateProperties">
  36. <dictionary>
  37. <!-- 方言 -->
  38. <entry key="dialect" value="NHibernate.Dialect.MsSql2008Dialect"/>
  39. <entry key="use_proxy_validator" value="false" />
  40. <entry key="show_sql" value="true"/>
  41. </dictionary>
  42. </property>
  43. <!-- 必须增加此项说明,与 Spring 的声明式事务集成 -->
  44. <property name="ExposeTransactionAwareSessionFactory" value="true" />
  45. </object>
  46. </objects>

其中connectionString="Data
Source=${db.server};Database=${db.database};User ID=${db.userid}
;PassWord=${db.password}中,我并没有明确指定他们访问地址、数据库等。这是一种类似定义一个变量的方式指定他们的访问地址、数
据库等信息的,具体变量的值是什么,会在后面web层的config配置文件中定义,按这个格式写就行,先不用纠结。这样也方便维护。

最后,还是看一下NHibernateDAO层的目录结构:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

『Spring.NET+NHibernate+泛型』框架搭建之BLL(四)

本节讲解业务逻辑层BLL。很简单和DAO层类似,通过泛型封装相似的功能到父类,其他子类继承父类即可,具体看下面操作。

一、业务逻辑接口层IBLL

1. 在解决方案上右键新建一个类库,命名为IBLL,用来存放业务逻辑接口层代码,并添加引用实体层Model,数据库访问接口层IDAO;

2. 在类库中添加一个父接口,命名为IBLL,并定义常用的方法,代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using IDAO;
  6. namespace IBLL
  7. {
  8. public interface IBLL<T>
  9. {
  10. IDAO<T> Dao { get; set; }
  11. /// <summary>
  12. /// 添加实体
  13. /// </summary>
  14. /// <param name="entity"></param>
  15. int Add(T entity);
  16. /// <summary>
  17. /// 修改实体
  18. /// </summary>
  19. /// <param name="entity"></param>
  20. void Update(T entity);
  21. /// <summary>
  22. /// 保存或修改实体
  23. /// </summary>
  24. /// <param name="customer"></param>
  25. void SaveOrUpdate(IList<T> list);
  26. /// <summary>
  27. /// 删除实体
  28. /// </summary>
  29. /// <param name="entity"></param>
  30. void Delete(T entity);
  31. /// <summary>
  32. /// 按条件删除
  33. /// </summary>
  34. /// <param name="sqlWhere">删除条件</param>
  35. void Delete(string sqlWhere);
  36. /// <summary>
  37. /// 根据ID得到实体
  38. /// </summary>
  39. /// <param name="id"></param>
  40. /// <returns></returns>
  41. T Get(int id);
  42. /// <summary>
  43. /// 根据ID得到实体
  44. /// </summary>
  45. /// <param name="id"></param>
  46. /// <returns></returns>
  47. T Load(int id);
  48. /// <summary>
  49. /// 得到所有实体
  50. /// </summary>
  51. /// <returns></returns>
  52. IList<T> LoadAll();
  53. /// <summary>
  54. /// 按条件排序得到前N条记录
  55. /// </summary>
  56. /// <param name="top">获取条数</param>
  57. /// <param name="field">排序字段</param>
  58. /// <param order="field">排序方式,升序asc,降序desc</param>
  59. /// <returns></returns>
  60. IList<T> QueryTop(int top, string field, string order = "asc");
  61. /// <summary>
  62. /// 根据条件得到实体
  63. /// </summary>
  64. /// <param name="sqlWhere">查询条件</param>
  65. /// <returns></returns>
  66. IList<T> Where(string sqlWhere="");
  67. /// <summary>
  68. /// 得到统计数量
  69. /// </summary>
  70. /// <param name="strWhere">查询条件</param>
  71. /// <returns></returns>
  72. int GetRecordCount(string strWhere = "");
  73. /// <summary>
  74. /// 分页获取数据列表
  75. /// </summary>
  76. /// <param name="PageSize">每页获取数据条数</param>
  77. /// <param name="PageIndex">当前页是第几页</param>
  78. /// <param name="strWhere">查询条件</param>
  79. /// <returns></returns>
  80. IList<T> GetPageList(int PageSize, int PageIndex, string strWhere = "");
  81. /// <summary>
  82. /// 根据数据字典父编码和编码获取名称
  83. /// </summary>
  84. /// <param name="parentNumber">父编码</param>
  85. /// <param name="number">编码</param>
  86. /// <returns></returns>
  87. string GetName(string parentNumber, string number);
  88. /// <summary>
  89. /// 获取该父编码下最大编码
  90. /// </summary>
  91. /// <param name="parentNumber">父编码</param>
  92. /// <returns></returns>
  93. string GetMaxNumber(string parentNumber);
  94. }
  95. }

3.定义好了父接口,下面定义子接口,还是以IT_RoleBLL为例,代码如下:

  1. using System;
  2. using Model;
  3. namespace IBLL
  4. {
  5. public interface IT_RoleBLL : IBLL<T_Role>
  6. {
  7. }
  8. }

这样,IT_RoleBLL就拥有了IBLL定义了的方法,如果IT_RoleBLL有特殊方法,直接添加在IT_RoleBLL里面即可,以IT_AreaBLL为例,代码如下:

  1. using Model;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. namespace IBLL
  7. {
  8. public interface IT_AreaBLL : IBLL<T_Area>
  9. {
  10. int GenerateAreaNumber(string parentNumber);
  11. }
  12. }

最后,我们看一下IBLL层的目录结构:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

二、业务逻辑实现层BLL

1. 在解决方案上右键新建一个类库,命名为BLL,用来存放业务逻辑实现层代码,并添加引用IBLL接口层、实体层Model和数据库访问接口层IDAO;

2. 在类库中添加一个父接口,命名为BLL,并定义常用的方法,代码如下:

  1. using IBLL;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using Model;
  7. using IDAO;
  8. namespace BLL
  9. {
  10. public class BLL<T>:IBLL<T>
  11. {
  12. public IDAO<T> Dao { get; set; }
  13. /// <summary>
  14. /// 添加实体
  15. /// </summary>
  16. /// <param name="entity"></param>
  17. public int Add(T entity)
  18. {
  19. return Dao.Add(entity);
  20. }
  21. /// <summary>
  22. /// 修改实体
  23. /// </summary>
  24. /// <param name="entity"></param>
  25. public void Update(T entity)
  26. {
  27. Dao.Update(entity);
  28. }
  29. /// <summary>
  30. /// 保存或修改实体
  31. /// </summary>
  32. /// <param name="customer"></param>
  33. public void SaveOrUpdate(IList<T> list)
  34. {
  35. Dao.SaveOrUpdate(list);
  36. }
  37. /// <summary>
  38. /// 删除实体
  39. /// </summary>
  40. /// <param name="entity"></param>
  41. public void Delete(T entity)
  42. {
  43. Dao.Delete(entity);
  44. }
  45. /// <summary>
  46. /// 按条件删除
  47. /// </summary>
  48. /// <param name="sqlWhere">删除条件</param>
  49. public void Delete(string sqlWhere)
  50. {
  51. Dao.Delete(sqlWhere);
  52. }
  53. /// <summary>
  54. /// 根据ID得到实体
  55. /// </summary>
  56. /// <param name="id"></param>
  57. /// <returns></returns>
  58. public T Get(int id)
  59. {
  60. return Dao.Get(id);
  61. }
  62. /// <summary>
  63. /// 根据ID得到实体
  64. /// </summary>
  65. /// <param name="id"></param>
  66. /// <returns></returns>
  67. public T Load(int id)
  68. {
  69. return Dao.Load(id);
  70. }
  71. /// <summary>
  72. /// 得到所有实体
  73. /// </summary>
  74. /// <returns></returns>
  75. public IList<T> LoadAll()
  76. {
  77. return Dao.LoadAll();
  78. }
  79. /// <summary>
  80. /// 按条件排序得到前N条记录
  81. /// </summary>
  82. /// <param name="top">获取条数</param>
  83. /// <param name="field">排序字段</param>
  84. /// <param order="field">排序方式,升序asc,降序desc</param>
  85. /// <returns></returns>
  86. public IList<T> QueryTop(int top, string field, string order = "asc")
  87. {
  88. return Dao.QueryTop(top,field,order);
  89. }
  90. /// <summary>
  91. /// 根据条件得到实体
  92. /// </summary>
  93. /// <param name="sqlWhere">查询条件</param>
  94. /// <returns></returns>
  95. public IList<T> Where(string sqlWhere = "")
  96. {
  97. return Dao.Where(sqlWhere);
  98. }
  99. /// <summary>
  100. /// 得到统计数量
  101. /// </summary>
  102. /// <param name="strWhere">查询条件</param>
  103. /// <returns></returns>
  104. public int GetRecordCount(string strWhere="")
  105. {
  106. return Dao.GetRecordCount(strWhere);
  107. }
  108. /// <summary>
  109. /// 分页获取数据列表
  110. /// </summary>
  111. /// <param name="PageSize">每页获取数据条数</param>
  112. /// <param name="PageIndex">当前页是第几页</param>
  113. /// <param name="strWhere">查询条件</param>
  114. /// <returns></returns>
  115. public IList<T> GetPageList(int PageSize, int PageIndex, string strWhere="")
  116. {
  117. return Dao.GetPageList(PageSize,PageIndex,strWhere);
  118. }
  119. /// <summary>
  120. /// 根据数据字典父编码和编码获取名称
  121. /// </summary>
  122. /// <param name="parentNumber">父编码</param>
  123. /// <param name="number">编码</param>
  124. /// <returns></returns>
  125. public string GetName(string parentNumber, string number)
  126. {
  127. return Dao.GetName(parentNumber, number);
  128. }
  129. /// <summary>
  130. /// 获取该父编码下最大编码
  131. /// </summary>
  132. /// <param name="parentNumber">父编码</param>
  133. /// <returns></returns>
  134. public string GetMaxNumber(string parentNumber)
  135. {
  136. int max = Dao.GetMaxNumber(parentNumber);
  137. return parentNumber + max.ToString().PadLeft(4, '0');
  138. }
  139. }
  140. }

3.定义好了父接口,下面定义子接口,以T_RoleBLL为例,代码如下:

  1. using System;
  2. using IBLL;
  3. using Model;
  4. namespace BLL
  5. {
  6. public class T_RoleBLL : BLL<T_Role>,IT_RoleBLL
  7. {
  8. }
  9. }

这样,T_RoleBLL就拥有了BLL定义了的方法,如果T_RoleBLL有特殊方法,直接添加在T_RoleBLL里面即可。不过要注意,对ITRoleDAO要单独实例化,原因:BLL中实例化的IDAO<T>对象仅仅是拥调用IDAO中定义的方法,并不拥有单独在子类定义的方法。以T_AreaBLL为例,代码如下:

  1. using IBLL;
  2. using IDAO;
  3. using Model;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. namespace BLL
  9. {
  10. public class T_AreaBLL : BLL<T_Area>,IT_AreaBLL
  11. {
  12. public IT_AreaDAO AreaDao { get; set; }
  13. public int GenerateAreaNumber(string parentNumber)
  14. {
  15. return AreaDao.GenerateAreaNumber(parentNumber);
  16. }
  17. }
  18. }

至于BLL中的Dao和T_AreaBLL中的AreaDao是如何被实例化的,我们在下一节再说!大家可以回忆一下DAO层中ISessionFactory对象SessionFactory是如何实例化的?这里用到了Spring.NET的依赖注入功能。最后,还是看一下BLL层的目录结构:

NHibernate框架与BLL+DAL+Model+Controller+UI  多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)