原文://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开发不熟),项目结构如下:
说明:
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各核心模块:
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表:
数据库表设计很简单,ID为主键,并且是自增长的,其他字段还包括角色名称(Name)、描述(Content)、排序(Sort)、状态(Status)、Del(是否删除)。这里就不对T_Role表赘述了。
T_Role类:
- using System;
- //Nhibernate Code Generation Template 1.0
- //author:MythXin
- //blog:www.cnblogs.com/MythXin
- //Entity Code Generation Template
- namespace Model{
- //T_Role
- public class T_Role
- {
- /// <summary>
- /// ID
- /// </summary>
- public virtual int ID
- {
- get;
- set;
- }
- /// <summary>
- /// Name
- /// </summary>
- public virtual string Name
- {
- get;
- set;
- }
- /// <summary>
- /// Content
- /// </summary>
- public virtual string Content
- {
- get;
- set;
- }
- /// <summary>
- /// Order
- /// </summary>
- public virtual int? Sort
- {
- get;
- set;
- }
- /// <summary>
- /// 1 启用(默认)
- ///0 禁用
- /// </summary>
- public virtual string Status
- {
- get;
- set;
- }
- /// <summary>
- /// 1 正常(默认)
- ///0 删除
- /// </summary>
- public virtual string Del
- {
- get;
- set;
- }
- }
- }
T_Role类必须与T_Role表的字段一一对应,名字可以不一样,但是字段属性数量和类型必须是一一对应的,此外,每个字段属性都必须为virtual的。
T_Role表与T_Role的映射文件:
- <?xml version="1.0" encoding="utf-8" ?>
- <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Model" >
- <class name="Model.T_Role, Model" table="T_Role">
- <id name="ID" column="ID" type="int" unsaved-value="0">
- <generator class="native"/>
- </id>
- <property name="Name" type="string" column="Name" />
- <property name="Content" type="string" column="Content" />
- <property name="Sort" type="int" column="Sort" />
- <property name="Status" type="string" column="Status" />
- <property name="Del" type="string" column="Del" />
- </class>
- </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的目录图,并不需要任何多余的引用:
『Spring.NET+NHibernate+泛型』框架搭建之DAO(三)★
本节内容介绍Nhibernate所封装的数据库访问层。不过我加入了泛型进行封装。大概思路:首先,我们有一个接口层,还有一个对应的实现层;在接口层 中我们先定义一个父接口,父接口中定义每一个接口都可能会用到的方法,然后其他接口继承此父接口即可。如果子接口需要使用特殊的方法,可以单独定义在子接 口中;在接口实现层中也是类似的,定义一个父类,里面写好实现了接口层父接口的方法,其他实现层同样继承父接口和实现层父类,接口层中定义的特殊方法也在 对应的实现类中进行实现。这样做可以有效的把相似的重复代码(重复的增删改查)尽可能的减少,并且这样设计比较灵活,重复的写一次就行了,特殊的单独写, 维护起来也比较方便。这样描述可能不是很明白,下面详细介绍实现步骤。
一、数据库访问接口层IDAO
1. 在解决方案上右键新建一个类库,命名为IDAO,用来存放Nhibernae数据库访问接口层代码,并添加引用上一节所讲的实体层Model;
2. 在类库中添加一个父接口,命名为IDAO,并定义常用的方法,代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace IDAO
- {
- public interface IDAO<T>
- {
- /// <summary>
- /// 添加实体
- /// </summary>
- /// <param name="entity"></param>
- int Add(T entity);
- /// <summary>
- /// 修改实体
- /// </summary>
- /// <param name="entity"></param>
- void Update(T entity);
- /// <summary>
- /// 保存或修改实体
- /// </summary>
- /// <param name="customer"></param>
- void SaveOrUpdate(IList<T> list);
- /// <summary>
- /// 删除实体
- /// </summary>
- /// <param name="entity"></param>
- void Delete(T entity);
- /// <summary>
- /// 按条件删除
- /// </summary>
- /// <param name="sqlWhere">删除条件</param>
- void Delete(string sqlWhere);
- /// <summary>
- /// 根据ID得到实体
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- T Get(int id);
- /// <summary>
- /// 根据ID得到实体
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- T Load(int id);
- /// <summary>
- /// 得到所有实体
- /// </summary>
- /// <returns></returns>
- IList<T> LoadAll();
- /// <summary>
- /// 按条件排序得到前N条记录
- /// </summary>
- /// <param name="top">获取条数</param>
- /// <param name="field">排序字段</param>
- /// <param order="field">排序方式,升序asc,降序desc</param>
- /// <returns></returns>
- IList<T> QueryTop(int top, string field, string order);
- /// <summary>
- /// 根据条件得到实体
- /// </summary>
- /// <param name="sqlWhere">查询条件</param>
- /// <returns></returns>
- IList<T> Where(string sqlWhere);
- /// <summary>
- /// 得到统计数量
- /// </summary>
- /// <param name="strWhere">查询条件</param>
- /// <returns></returns>
- int GetRecordCount(string strWhere);
- /// <summary>
- /// 分页获取数据列表
- /// </summary>
- /// <param name="PageSize">每页获取数据条数</param>
- /// <param name="PageIndex">当前页是第几页</param>
- /// <param name="strWhere">查询条件</param>
- /// <returns></returns>
- IList<T> GetPageList(int PageSize, int PageIndex, string strWhere);
- /// <summary>
- /// 根据数据字典父编码和编码获取名称
- /// </summary>
- /// <param name="parentNumber">父编码</param>
- /// <param name="number">编码</param>
- /// <returns></returns>
- string GetName(string parentNumber, string number);
- /// <summary>
- /// 获取该父编码下最大编码
- /// </summary>
- /// <param name="parentNumber">父编码</param>
- /// <returns></returns>
- int GetMaxNumber(string parentNumber);
- }
- }
3.定义好了父接口,下面定义子接口,还是以IT_RoleDAO为例,代码如下:
- using System;
- using Model;
- namespace IDAO
- {
- public interface IT_RoleDAO : IDAO<T_Role>
- {
- }
- }
这样,IT_RoleDAO就拥有了IDAO定义了的方法,如果IT_RoleDAO有特殊方法,直接添加在IT_RoleDAO里面即可,以IT_AreaDAO为例,代码如下:
- using System;
- using Model;
- namespace IDAO
- {
- public interface IT_AreaDAO : IDAO<T_Area>
- {
- /// <summary>
- /// 获取
- /// </summary>
- /// <param name="parentNumber"></param>
- /// <returns></returns>
- int GenerateAreaNumber(string parentNumber);
- }
- }
最后,我们看一下IDAO层的文件目录:
二、NHibernate数据库访问实现层NHibernateDAO(核心)
1. 在解决方案上右键新建一个类库,命名为NHibernateDAO,用来存放Nhibernae数据库访问实现层代码,并添加引用上一节所讲的实体层Model和接口层IDAO;
2. 右键点击引用,选择“管理NuGet程序包”,选择“联机”,搜索
“Spring.NET”,在搜索结果中选择“Spring.Net NHibernate 4
support”安装。该安装包括了一个NHibernate,但是还不够,同样的方法搜索NHibernate,并安装,添加Nhibernate就不上图了,添加Spring.NET的界面图如下:
3.添加数据库访问层父类NHibernateDAO,NHibernateDAO类中的SessionFactory属性的
GetCurrentSession方法可以实例化ISession,实例化ISession后的对象可以调用NHibernate下的数据库操作方法,
具体他们之间怎么实例化,先上代码,后面再来解释。
NHibernateDAO代码如下,继承INHibernateSessionFactory和实现IDAO父接口:
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using Model;
- using IDAO;
- using NHibernate;
- using NHibernate.Criterion;
- using NHibernate.Linq;
- using Spring.Data.NHibernate.Support;
- using NHibernate.Cfg;
- using System.Text;
- namespace NHibernateDAO
- {
- [Spring.Stereotype.Repository]
- public class NHibernateDAO<T> : IDAO<T>
- {
- public ISessionFactory SessionFactory { get; set; }
- /// <summary>
- /// 获取Session
- /// </summary>
- public ISession Session
- {
- get
- {
- return SessionFactory.GetCurrentSession();
- }
- }
- /// <summary>
- /// 当前实体对应的表名
- /// </summary>
- public string TableName
- {
- get { return typeof(T).ToString().Substring(typeof(T).ToString().LastIndexOf('.') + 1); }
- }
- /// <summary>
- /// 添加实体
- /// </summary>
- /// <param name="entity"></param>
- public int Add(T entity)
- {
- using (ITransaction transaction = Session.BeginTransaction())
- {
- try
- {
- int id = (int)Session.Save(entity);
- Session.Flush();
- transaction.Commit();
- return id;
- }
- catch (HibernateException)
- {
- transaction.Rollback();
- throw;
- }
- }
- }
- /// <summary>
- /// 修改实体
- /// </summary>
- /// <param name="entity"></param>
- public void Update(T entity)
- {
- using (ITransaction transaction = Session.BeginTransaction())
- {
- try
- {
- Session.Update(entity);
- Session.Flush();
- transaction.Commit();
- }
- catch (HibernateException)
- {
- transaction.Rollback();
- throw;
- }
- }
- }
- /// <summary>
- /// 保存或修改实体
- /// </summary>
- /// <param name="customer"></param>
- public void SaveOrUpdate(IList<T> list)
- {
- using (ITransaction transaction = Session.BeginTransaction())
- {
- try
- {
- foreach (var entity in list)
- {
- Session.SaveOrUpdate(entity);
- }
- Session.Flush();
- transaction.Commit();
- }
- catch (HibernateException)
- {
- transaction.Rollback();
- throw;
- }
- }
- }
- /// <summary>
- /// 删除实体
- /// </summary>
- /// <param name="entity"></param>
- public void Delete(T entity)
- {
- using (ITransaction transaction = Session.BeginTransaction())
- {
- try
- {
- Session.Delete(entity);
- Session.Flush();
- transaction.Commit();
- }
- catch (HibernateException)
- {
- transaction.Rollback();
- throw;
- }
- }
- }
- /// <summary>
- /// 按条件删除
- /// </summary>
- /// <param name="sqlWhere">删除条件</param>
- public void Delete(string sqlWhere)
- {
- using (ITransaction transaction = Session.BeginTransaction())
- {
- try
- {
- Session.Delete(string.Format("from {0} Where {1}", TableName, sqlWhere));
- Session.Flush();
- transaction.Commit();
- }
- catch (HibernateException)
- {
- transaction.Rollback();
- throw;
- }
- }
- }
- /// <summary>
- /// 根据ID得到实体
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- public T Get(int id)
- {
- return Session.Get<T>(id);
- }
- /// <summary>
- /// 根据ID得到实体
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- public T Load(int id)
- {
- return Session.Load<T>(id);
- }
- /// <summary>
- /// 得到所有实体
- /// </summary>
- /// <returns></returns>
- public IList<T> LoadAll()
- {
- return Session.Query<T>().ToList();
- }
- /// <summary>
- /// 按条件排序得到前N条记录
- /// </summary>
- /// <param name="top">获取条数</param>
- /// <param name="field">排序字段</param>
- /// <param order="field">排序方式,升序asc,降序desc</param>
- /// <returns></returns>
- public IList<T> QueryTop(int top, string field, string order)
- {
- if (order == "asc")
- {
- return Session.CreateCriteria(typeof(T)).SetMaxResults(top).AddOrder(Order.Asc(field)).List<T>();
- }
- else
- {
- return Session.CreateCriteria(typeof(T)).SetMaxResults(top).AddOrder(Order.Desc(field)).List<T>();
- }
- }
- /// <summary>
- /// 根据条件得到实体
- /// </summary>
- /// <param name="sqlWhere">查询条件</param>
- /// <returns></returns>
- public IList<T> Where(string sqlWhere)
- {
- StringBuilder strSql = new StringBuilder(string.Format("from {0} c", TableName));
- if (!string.IsNullOrEmpty(sqlWhere))
- {
- strSql.Append(string.Format(" where {0}", sqlWhere));
- }
- return Session.CreateQuery(strSql.ToString()).List<T>();
- }
- /// <summary>
- /// 得到统计数量
- /// </summary>
- /// <param name="strWhere">查询条件</param>
- /// <returns></returns>
- public int GetRecordCount(string sqlWhere)
- {
- StringBuilder strSql = new StringBuilder(string.Format("select count(1) from {0} c", TableName));
- if (!string.IsNullOrEmpty(sqlWhere))
- {
- strSql.Append(string.Format(" where {0}", sqlWhere));
- }
- return (int)Session.CreateSQLQuery(strSql.ToString()).UniqueResult();
- }
- /// <summary>
- /// 分页获取数据列表
- /// </summary>
- /// <param name="PageSize">每页获取数据条数</param>
- /// <param name="PageIndex">当前页是第几页</param>
- /// <param name="strWhere">查询条件</param>
- /// <returns></returns>
- public IList<T> GetPageList(int PageSize, int PageIndex, string sqlWhere)
- {
- StringBuilder strSql = new StringBuilder();
- strSql.Append(string.Format("select top {0} * from {1} where ID not in(select top ", PageSize,
- TableName));
- strSql.Append(PageSize * (PageIndex - 1));
- strSql.Append(string.Format(" ID from {0}", TableName));
- if (!string.IsNullOrEmpty(sqlWhere))
- {
- strSql.Append(string.Format(" where {0} ) and {0}", sqlWhere));
- }
- else
- {
- strSql.Append(")");
- }
- return Session.CreateSQLQuery(strSql.ToString()).AddEntity(typeof(T)).List<T>();
- }
- /// <summary>
- /// 根据数据字典父编码和编码获取名称
- /// </summary>
- /// <param name="parentNumber">父编码</param>
- /// <param name="number">编码</param>
- /// <returns></returns>
- public string GetName(string parentNumber, string number)
- {
- string[] num = number.Split(',');
- List<string> list = new List<string>();
- list.AddRange(num);
- IQueryable<string> name = from q in Session.Query<T_Dictionary>()
- where q.ParentNumber == parentNumber && list.Contains(q.Number) orderby q.Number
- select q.Name;
- string nameStr = "";
- foreach (string n in name)
- {
- nameStr += n + ",";
- }
- return nameStr.Contains(",") ? nameStr.Substring(0, nameStr.Length - 1) : nameStr;
- }
- /// <summary>
- /// 获取该父编码下最大编码
- /// </summary>
- /// <param name="parentNumber">父编码</param>
- /// <returns></returns>
- public int GetMaxNumber(string parentNumber)
- {
- string strSql =
- string.Format(
- "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}'",
- TableName, parentNumber);
- return ++Session.CreateQuery(strSql).List<int>()[0];
- }
- }
- }
4. 添加一个数据库访问层实现类,以T_RoleDAO为例:
- using System;
- using System.Collections;
- using IDAO;
- using Model;
- namespace NHibernateDAO
- {
- public class T_RoleDAO : NHibernateDAO<T_Role>, IT_RoleDAO
- {
- }
- }
同样滴,继承NHibernateDAO并实现IT_RoleDAO接口,他便拥有了他们定义好的方法。如果有特殊方法代码如下:
- using System;
- using System.Collections;
- using Model;
- using IDAO;
- using System.Text;
- using System.Collections.Generic;
- using NHibernate;
- namespace NHibernateDAO
- {
- public class T_AreaDAO : NHibernateDAO<T_Area>,IT_AreaDAO
- {
- public int GenerateAreaNumber(string parentNumber)
- {
- string sqlStr = string.Format(@"select case when MAX(cast(Number as int)) is null then 0
- else MAX(cast(Number as int)) end
- from {0}
- where ParentNumber={1}", TableName, parentNumber);
- return ++Session.CreateQuery(sqlStr).List<int>()[0];
- }
- }
- }
5.
下面,就来解释一下他们都是怎么实例化的。这里就用到Spring.NET依赖注入的方式实现,先看配置文件。在NHibernateDAO类库下添加文
件夹Config,用来存放配置文件,然后添加一个命名为objects.xml的xml。这里必须定义每一个数据库访问层对象,不能说他们都继承
NHibernateDAO,只定义NHibernateDAO,这样的话会报错,因为后面BLL层要调用DAO层,他们之间是一一对应的,这里先简单提
一下,后面讲到就明白了。代码如下:
- <?xml version="1.0" encoding="utf-8" ?>
- <objects xmlns="http://www.springframework.net">
- <!--T_AreaDAO,管理T_Area的对象-->
- <object id="T_AreaDAO" type="NHibernateDAO.T_AreaDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_AssessmentCoefficientDAO,管理T_AssessmentCoefficient的对象-->
- <object id="T_AssessmentCoefficientDAO" type="NHibernateDAO.T_AssessmentCoefficientDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_AuthorityDAO,管理T_Authority的对象-->
- <object id="T_AuthorityDAO" type="NHibernateDAO.T_AuthorityDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_ClientDAO,管理T_Client的对象-->
- <object id="T_ClientDAO" type="NHibernateDAO.T_ClientDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_DictionaryDAO,管理T_Dictionary的对象-->
- <object id="T_DictionaryDAO" type="NHibernateDAO.T_DictionaryDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_DrugDAO,管理T_Drug的对象-->
- <object id="T_DrugDAO" type="NHibernateDAO.T_DrugDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_InvoicingCollectDetailDAO,管理T_InvoicingCollectDetail的对象-->
- <object id="T_InvoicingCollectDetailDAO" type="NHibernateDAO.T_InvoicingCollectDetailDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_InvoicingDetailDAO,管理T_InvoicingDetail的对象-->
- <object id="T_InvoicingDetailDAO" type="NHibernateDAO.T_InvoicingDetailDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_LogDAO,管理T_Log的对象-->
- <object id="T_LogDAO" type="NHibernateDAO.T_LogDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_MenuDAO,管理T_Menu的对象-->
- <object id="T_MenuDAO" type="NHibernateDAO.T_MenuDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_OpHistoryDAO,管理T_OpHistory的对象-->
- <object id="T_OpHistoryDAO" type="NHibernateDAO.T_OpHistoryDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_RoleDAO,管理T_Role的对象-->
- <object id="T_RoleDAO" type="NHibernateDAO.T_RoleDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_UserDAO,管理T_User的对象-->
- <object id="T_UserDAO" type="NHibernateDAO.T_UserDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--V_InvoicingCollectDetailDAO,管理V_InvoicingCollectDetail的对象-->
- <object id="V_InvoicingCollectDetailDAO" type="NHibernateDAO.V_InvoicingCollectDetailDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--V_InvoicingDetailDAO,管理V_InvoicingDetail的对象-->
- <object id="V_InvoicingDetailDAO" type="NHibernateDAO.V_InvoicingDetailDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--V_TrackDAO,管理V_Track的对象-->
- <object id="V_TrackDAO" type="NHibernateDAO.V_TrackDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--V_CoverageRateDAO,管理V_CoverageRate的对象-->
- <object id="V_CoverageRateDAO" type="NHibernateDAO.V_CoverageRateDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--V_AssessDAO,管理V_Assess的对象-->
- <object id="V_AssessDAO" type="NHibernateDAO.V_AssessDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- <!--T_BuyDetailDAO,管理T_BuyDetail的对象-->
- <object id="T_BuyDetailDAO" type="NHibernateDAO.T_BuyDetailDAO,NHibernateDAO">
- <property name="SessionFactory" ref="NHibernateSessionFactory"/>
- </object>
- </objects>
格式如上述代码,先定义一个objects根节点,然后再objects中定义每一
个数据库访层,type指定“命名空间.类名,命名空间”,property指定属性,name必须与NHibernateDAO中的
SessionFactory相同,由于每一个数据库访问层都继承了NHibernateDAO,所有他们就拥有了NHibernateDAO的属性
SessionFactory,ref指定SessionFactory实例化的对象,NHibernateSessionFactory是
NHibernate框架封装的数据库访问类。所以,我们看到我们没有在代码中实实例化SessionFactory,只是定义了一个属性,而是通过Spring.NET的配置文件来把SessionFactory实例化的,这就是所谓的依赖注入,也交控制反转。
6. 细心的撸友可以发现了,数据库操作的类和方法我们定义好了,但是数据访问的连接字符串还没有,下面就来配置数据库访问文件。同样在NHibernateDAO的Config中添加DataAccess.xml,代码如下:
- <?xml version="1.0" encoding="utf-8" ?>
- <objects xmlns="http://www.springframework.net"
- xmlns:db="http://www.springframework.net/database"
- xmlns:tx="http://www.springframework.net/tx"
- >
- <!--描述-->
- <description>
- 数据访问的配置信息
- 包括:DbProvider
- NHibernate
- </description>
- <!-- 通过主应用程序的上下文配置文件引用 -->
- <object type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
- <property name="ConfigSections" value="spring/databaseSettings"/>
- </object>
- <!-- 数据库的配置 -->
- <db:provider id="DbProvider"
- provider="SqlServer-2.0"
- connectionString="Data Source=${db.server};Database=${db.database};User ID=${db.userid} ;PassWord=${db.password}"
- />
- <!-- NHibernate 配置 -->
- <!-- 可以通过 name 为其指定别名 name="SessionFactory" -->
- <object id="NHibernateSessionFactory"
- type="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate4"
- >
- <!-- 关于数据库连接的配置,直接使用 DbProvider 中的设置,这样,不需要为 Hibernate 再提供连接串和驱动 -->
- <property name="DbProvider" ref="DbProvider"/>
- <!-- 包含有映射文件的程序集,需要分析的hbm程序集名称 -->
- <property name="MappingAssemblies">
- <list>
- <value>Model</value>
- </list>
- </property>
- <!-- 其他的参数 -->
- <property name="HibernateProperties">
- <dictionary>
- <!-- 方言 -->
- <entry key="dialect" value="NHibernate.Dialect.MsSql2008Dialect"/>
- <entry key="use_proxy_validator" value="false" />
- <entry key="show_sql" value="true"/>
- </dictionary>
- </property>
- <!-- 必须增加此项说明,与 Spring 的声明式事务集成 -->
- <property name="ExposeTransactionAwareSessionFactory" value="true" />
- </object>
- </objects>
其中connectionString="Data
Source=${db.server};Database=${db.database};User ID=${db.userid}
;PassWord=${db.password}中,我并没有明确指定他们访问地址、数据库等。这是一种类似定义一个变量的方式指定他们的访问地址、数
据库等信息的,具体变量的值是什么,会在后面web层的config配置文件中定义,按这个格式写就行,先不用纠结。这样也方便维护。
最后,还是看一下NHibernateDAO层的目录结构:
『Spring.NET+NHibernate+泛型』框架搭建之BLL(四)
本节讲解业务逻辑层BLL。很简单和DAO层类似,通过泛型封装相似的功能到父类,其他子类继承父类即可,具体看下面操作。
一、业务逻辑接口层IBLL
1. 在解决方案上右键新建一个类库,命名为IBLL,用来存放业务逻辑接口层代码,并添加引用实体层Model,数据库访问接口层IDAO;
2. 在类库中添加一个父接口,命名为IBLL,并定义常用的方法,代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using IDAO;
- namespace IBLL
- {
- public interface IBLL<T>
- {
- IDAO<T> Dao { get; set; }
- /// <summary>
- /// 添加实体
- /// </summary>
- /// <param name="entity"></param>
- int Add(T entity);
- /// <summary>
- /// 修改实体
- /// </summary>
- /// <param name="entity"></param>
- void Update(T entity);
- /// <summary>
- /// 保存或修改实体
- /// </summary>
- /// <param name="customer"></param>
- void SaveOrUpdate(IList<T> list);
- /// <summary>
- /// 删除实体
- /// </summary>
- /// <param name="entity"></param>
- void Delete(T entity);
- /// <summary>
- /// 按条件删除
- /// </summary>
- /// <param name="sqlWhere">删除条件</param>
- void Delete(string sqlWhere);
- /// <summary>
- /// 根据ID得到实体
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- T Get(int id);
- /// <summary>
- /// 根据ID得到实体
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- T Load(int id);
- /// <summary>
- /// 得到所有实体
- /// </summary>
- /// <returns></returns>
- IList<T> LoadAll();
- /// <summary>
- /// 按条件排序得到前N条记录
- /// </summary>
- /// <param name="top">获取条数</param>
- /// <param name="field">排序字段</param>
- /// <param order="field">排序方式,升序asc,降序desc</param>
- /// <returns></returns>
- IList<T> QueryTop(int top, string field, string order = "asc");
- /// <summary>
- /// 根据条件得到实体
- /// </summary>
- /// <param name="sqlWhere">查询条件</param>
- /// <returns></returns>
- IList<T> Where(string sqlWhere="");
- /// <summary>
- /// 得到统计数量
- /// </summary>
- /// <param name="strWhere">查询条件</param>
- /// <returns></returns>
- int GetRecordCount(string strWhere = "");
- /// <summary>
- /// 分页获取数据列表
- /// </summary>
- /// <param name="PageSize">每页获取数据条数</param>
- /// <param name="PageIndex">当前页是第几页</param>
- /// <param name="strWhere">查询条件</param>
- /// <returns></returns>
- IList<T> GetPageList(int PageSize, int PageIndex, string strWhere = "");
- /// <summary>
- /// 根据数据字典父编码和编码获取名称
- /// </summary>
- /// <param name="parentNumber">父编码</param>
- /// <param name="number">编码</param>
- /// <returns></returns>
- string GetName(string parentNumber, string number);
- /// <summary>
- /// 获取该父编码下最大编码
- /// </summary>
- /// <param name="parentNumber">父编码</param>
- /// <returns></returns>
- string GetMaxNumber(string parentNumber);
- }
- }
3.定义好了父接口,下面定义子接口,还是以IT_RoleBLL为例,代码如下:
- using System;
- using Model;
- namespace IBLL
- {
- public interface IT_RoleBLL : IBLL<T_Role>
- {
- }
- }
这样,IT_RoleBLL就拥有了IBLL定义了的方法,如果IT_RoleBLL有特殊方法,直接添加在IT_RoleBLL里面即可,以IT_AreaBLL为例,代码如下:
- using Model;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace IBLL
- {
- public interface IT_AreaBLL : IBLL<T_Area>
- {
- int GenerateAreaNumber(string parentNumber);
- }
- }
最后,我们看一下IBLL层的目录结构:
二、业务逻辑实现层BLL
1. 在解决方案上右键新建一个类库,命名为BLL,用来存放业务逻辑实现层代码,并添加引用IBLL接口层、实体层Model和数据库访问接口层IDAO;
2. 在类库中添加一个父接口,命名为BLL,并定义常用的方法,代码如下:
- using IBLL;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Model;
- using IDAO;
- namespace BLL
- {
- public class BLL<T>:IBLL<T>
- {
- public IDAO<T> Dao { get; set; }
- /// <summary>
- /// 添加实体
- /// </summary>
- /// <param name="entity"></param>
- public int Add(T entity)
- {
- return Dao.Add(entity);
- }
- /// <summary>
- /// 修改实体
- /// </summary>
- /// <param name="entity"></param>
- public void Update(T entity)
- {
- Dao.Update(entity);
- }
- /// <summary>
- /// 保存或修改实体
- /// </summary>
- /// <param name="customer"></param>
- public void SaveOrUpdate(IList<T> list)
- {
- Dao.SaveOrUpdate(list);
- }
- /// <summary>
- /// 删除实体
- /// </summary>
- /// <param name="entity"></param>
- public void Delete(T entity)
- {
- Dao.Delete(entity);
- }
- /// <summary>
- /// 按条件删除
- /// </summary>
- /// <param name="sqlWhere">删除条件</param>
- public void Delete(string sqlWhere)
- {
- Dao.Delete(sqlWhere);
- }
- /// <summary>
- /// 根据ID得到实体
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- public T Get(int id)
- {
- return Dao.Get(id);
- }
- /// <summary>
- /// 根据ID得到实体
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- public T Load(int id)
- {
- return Dao.Load(id);
- }
- /// <summary>
- /// 得到所有实体
- /// </summary>
- /// <returns></returns>
- public IList<T> LoadAll()
- {
- return Dao.LoadAll();
- }
- /// <summary>
- /// 按条件排序得到前N条记录
- /// </summary>
- /// <param name="top">获取条数</param>
- /// <param name="field">排序字段</param>
- /// <param order="field">排序方式,升序asc,降序desc</param>
- /// <returns></returns>
- public IList<T> QueryTop(int top, string field, string order = "asc")
- {
- return Dao.QueryTop(top,field,order);
- }
- /// <summary>
- /// 根据条件得到实体
- /// </summary>
- /// <param name="sqlWhere">查询条件</param>
- /// <returns></returns>
- public IList<T> Where(string sqlWhere = "")
- {
- return Dao.Where(sqlWhere);
- }
- /// <summary>
- /// 得到统计数量
- /// </summary>
- /// <param name="strWhere">查询条件</param>
- /// <returns></returns>
- public int GetRecordCount(string strWhere="")
- {
- return Dao.GetRecordCount(strWhere);
- }
- /// <summary>
- /// 分页获取数据列表
- /// </summary>
- /// <param name="PageSize">每页获取数据条数</param>
- /// <param name="PageIndex">当前页是第几页</param>
- /// <param name="strWhere">查询条件</param>
- /// <returns></returns>
- public IList<T> GetPageList(int PageSize, int PageIndex, string strWhere="")
- {
- return Dao.GetPageList(PageSize,PageIndex,strWhere);
- }
- /// <summary>
- /// 根据数据字典父编码和编码获取名称
- /// </summary>
- /// <param name="parentNumber">父编码</param>
- /// <param name="number">编码</param>
- /// <returns></returns>
- public string GetName(string parentNumber, string number)
- {
- return Dao.GetName(parentNumber, number);
- }
- /// <summary>
- /// 获取该父编码下最大编码
- /// </summary>
- /// <param name="parentNumber">父编码</param>
- /// <returns></returns>
- public string GetMaxNumber(string parentNumber)
- {
- int max = Dao.GetMaxNumber(parentNumber);
- return parentNumber + max.ToString().PadLeft(4, '0');
- }
- }
- }
3.定义好了父接口,下面定义子接口,以T_RoleBLL为例,代码如下:
- using System;
- using IBLL;
- using Model;
- namespace BLL
- {
- public class T_RoleBLL : BLL<T_Role>,IT_RoleBLL
- {
- }
- }
这样,T_RoleBLL就拥有了BLL定义了的方法,如果T_RoleBLL有特殊方法,直接添加在T_RoleBLL里面即可。不过要注意,对ITRoleDAO要单独实例化,原因:BLL中实例化的IDAO<T>对象仅仅是拥调用IDAO中定义的方法,并不拥有单独在子类定义的方法。以T_AreaBLL为例,代码如下:
- using IBLL;
- using IDAO;
- using Model;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace BLL
- {
- public class T_AreaBLL : BLL<T_Area>,IT_AreaBLL
- {
- public IT_AreaDAO AreaDao { get; set; }
- public int GenerateAreaNumber(string parentNumber)
- {
- return AreaDao.GenerateAreaNumber(parentNumber);
- }
- }
- }
至于BLL中的Dao和T_AreaBLL中的AreaDao是如何被实例化的,我们在下一节再说!大家可以回忆一下DAO层中ISessionFactory对象SessionFactory是如何实例化的?这里用到了Spring.NET的依赖注入功能。最后,还是看一下BLL层的目录结构: