- 你所在位置:首页 〉VS.net〉ASP.net〉开发〉.net企业级架构实战之4—Spring.net下的nHibernate数据访问模板
- .net企业级架构实战之4—Spring.net下的nHibernate数据访问模板
- 作者:莫耶 文章来源:博客园 发布日期:2008-11-15 浏览次数:92
-
- 打印这篇文章
-
在spring.net中集成nHibernate可以获得许多值得称道的特性。比如:基于元标记(meta Attributes)的事务支持、对物理数据库的抽象、对数据层进行切面式拦截。
好处是不少,但首先要学会配置。为了这个集成的环境,建立一个配置文件 applicationContext.xml :

Code
〈?xml version="1.0" encoding="utf-8" ?>
〈objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"
>
〈!--spring集合nHibernate-->
〈object id="DbProvider" type="woodigg.DAO.SQLProvider,woodigg.DAO">
〈property name="ConnectionString"
value="Server=(local);database=Music;User Id=sa;Password=******;Trusted_Connection=False" />
〈/object>
〈!--session工厂-->
〈object id="SessionFactory"
type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
〈property name="DbProvider" ref="DbProvider" />
〈property name="MappingAssemblies">
〈list>
〈value>woodigg.DAO〈/value>
〈value>woodigg.model〈/value>
〈/list>
〈/property>
〈property name="HibernateProperties">
〈dictionary>
〈entry key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
〈entry key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
〈entry key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
〈entry key="show_sql" value="false" />
〈entry key="hibernate.current_session_context_class" value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12"/>
〈entry key="hibernate.query.factory_class" value="NHibernate.Hql.Classic.ClassicQueryTranslatorFactory" />
〈entry key="hibernate.cache.provider_class" value="NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache" />
〈entry key="relativeExpiration" value="5" />
〈/dictionary>
〈/property>
〈/object>
〈!--事务管理器-->
〈object id="HibernateTransactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate12">
〈property name="DbProvider" ref="DbProvider" />
〈property name="SessionFactory" ref="SessionFactory" />
〈/object>
〈!--事务拦截器-->
〈object id="TransactionInterceptor"
type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
〈property name="TransactionManager" ref="HibernateTransactionManager" />
〈property name="TransactionAttributeSource">
〈object type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data" />
〈/property>
〈/object>
〈!--HibernateTemplate-->
〈object id="HibernateTemplate"
type="Spring.Data.NHibernate.HibernateTemplate,Spring.Data.NHibernate12">
〈property name="SessionFactory" ref="SessionFactory" />
〈/object>
〈!--Dao代理模板-->
〈object id="DaoTemplate" type="woodigg.DAO.DaoTemplate, woodigg.DAO">
〈property name="SessionFactory" ref="SessionFactory" />
〈/object>
〈/objects>
OK,这里有几处需要说明:
一、woodigg.DAO.SQLProvider 是一个数据结构类,用以描述物理数据库的相关信息,诸如连接串、元数据信息等。这里其实就用到了连接串,在配置中植入位置、帐号信息等就能连接到数据源。这个SQLProvider类结构如下:
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Spring.Data.Common;
namespace woodigg.DAO
{
public class SQLProvider : IDbProvider
{
#region IDbProvider 成员
private string _connectionString = "";
public string ConnectionString
{
get
{
return this._connectionString;
}
set
{
this._connectionString = value;
}
}
public IDbCommand CreateCommand()
{
return null;
}
public object CreateCommandBuilder()
{
return null;
}
public IDbConnection CreateConnection()
{
return null;
}
public IDbDataAdapter CreateDataAdapter()
{
return null;
}
public IDbDataParameter CreateParameter()
{
return null;
}
public string CreateParameterName(string name)
{
return null;
}
public string CreateParameterNameForCollection(string name)
{
return null;
}
public IDbMetadata DbMetadata
{
get
{
return null;
}
}
public string ExtractError(Exception e)
{
return null;
}
public bool IsDataAccessException(Exception e)
{
return false;
}
#endregion
}
}
二、在SessionFactory配置中,指明需要环境映射的程序集名称,通俗说法是:哪些层会在集成环境中,被直接引用?这里以示例项目来说是:woodigg.DAO和woodigg.Model,分别为实体(上一节中生成的一堆.cs实体)层,和数据映射文件(被嵌入在项目中的hbm.xml文件)所在的数据访问层。
三、HibernateProperties节中,可以指定调试时是否显示生成的sql语句。同时,能配置缓存事宜:此处用到的是NHibernate.Caches.SysCache。
四、配置HibernateTemplate。nHibernate的模板,既nHibernate项目已经为开发者写好了一套通用的方法,能便捷的操作数据库,此处将SessionFactory植入引用即能让它工作起来。(并不是所有的复杂SQL,它都能做到,不能完成的功能,我们得自己写,这个马上会交待)。
五、DaoTemplate,就是我自己写的一个基于以上配置的复杂模板,能完成诸如Distinct,top,调用分页存储过程等一干复杂SQL功能,抛出来做点贡献吧:
Code
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Engine;
using NHibernate.Expression;
using Spring.Dao;
using Spring.Data.NHibernate.Support;
using woodigg.model;
using log4net;
namespace woodigg.DAO
{
#region ParamInfo结构
public struct ParamInfo
{
public string Name;
public object Value;
}
#endregion
/// 〈summary>
/// 继续自HibernateDaoSupport抽象类
/// HibernateDaoSupport基类拥有HibernateTemplate
/// 〈/summary>
public class DaoTemplate : HibernateDaoSupport
{
/// 〈summary>
/// 泛型读取
/// 〈/summary>
/// 〈param name="obj">〈/param>
/// 〈param name="id">〈/param>
#region T LoadFromId〈T>(object id)
public T LoadFromId〈T>(object id)
{
try
{
T obj =
(T)HibernateTemplate.Load(typeof(T), id);
return obj;
}
catch (Exception ex)
{
ILog log = LogManager.GetLogger(typeof(T));
log.Error(ex.Message, ex);
return default(T);
}
}
#endregion
/// 〈summary>
/// 泛型存储
/// 〈/summary>
/// 〈typeparam name="T">〈/typeparam>
/// 〈param name="obj">〈/param>
#region bool Save〈T>(T obj)
public bool Save〈T>(T obj)
{
try
{
HibernateTemplate.Save(obj);
return true;
}
catch (DataAccessException ex)
{
ILog log = LogManager.GetLogger(typeof(T));
log.Error(ex.Message, ex);
return false;
}
}
#endregion
/// 〈summary>
/// 泛型更新
/// 〈/summary>
/// 〈typeparam name="T">〈/typeparam>
/// 〈param name="obj">〈/param>
#region bool Update〈T>(T obj)
public bool Update〈T>(T obj)
{
try
{
HibernateTemplate.Update(obj);
return true;
}
catch (DataAccessException ex)
{
ILog log = LogManager.GetLogger(typeof(T));
log.Error(ex.Message, ex);
return false;
}
}
#endregion
/// 〈summary>
/// 泛型删除
/// 〈/summary>
/// 〈typeparam name="T">〈/typeparam>
/// 〈param name="obj">〈/param>
#region bool Delete〈T>(T obj)
public bool Delete〈T>(T obj)
{
try
{
HibernateTemplate.Delete(obj);
return true;
}
catch (DataAccessException ex)
{
ILog log = LogManager.GetLogger(typeof(T));
log.Error(ex.Message, ex);
return false;
}
}
#endregion
/// 〈summary>
/// 条件删除
/// 〈/summary>
/// 〈typeparam name="T">〈/typeparam>
/// 〈param name="where">〈/param>
#region bool Delete〈T>(string where)
public bool Delete〈T>(string where)
{
try
{
string sql =string.Format("from {0} {1}",
typeof(T).ToString(),
where.ToUpper().StartsWith("WHERE") ? where : "WHERE " + where);
HibernateTemplate.Delete(sql);
return true;
}
catch (DataAccessException ex)
{
ILog log = LogManager.GetLogger(typeof(T));
log.Error(ex.Message, ex);
return false;
}
}
#endregion
/// 〈summary>
/// 泛型搜索
/// 〈/summary>
/// 〈typeparam name="T">〈/typeparam>
/// 〈param name="where">〈/param>
#region IList〈T> Search〈T>(string where)
public IList〈T> Search〈T>(string where)
{
try
{
//有意思的模板反射哟~
T obj = (T)System.Reflection.Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).ToString());
string hql = string.Format("from {0} {1}",
obj.GetType().ToString(),
where.ToUpper().StartsWith("WHERE") ? where : "WHERE " + where);
IList alist = HibernateTemplate.Find(hql);
IList〈T> list = new List〈T>();
if (alist != null && alist.Count > 0)
{
foreach (T t in alist)
{ list.Add(t); }
return list;
}
else
return null;
}
catch (Exception ex)
{
ILog log = LogManager.GetLogger(typeof(T));
log.Error(ex.Message, ex);
return null;
}
}
#endregion
/// 〈summary>
/// 泛型搜索 - DISTINCT
/// 〈/summary>
/// 〈typeparam name="T">〈/typeparam>
/// 〈param name="field">列名,用","分开,不带别名〈/param>
/// 〈param name="where">〈/param>
/// 〈param name="alias">别名〈/param>
#region IList〈T> SearchDistinct〈T>(string where,string field,string alias)
public IList〈T> SearchDistinct〈T>(string where, string field, string alias)
{
try
{
//有意思的模板反射哟~
T obj = (T)System.Reflection.Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).ToString());
// 反射DTO对象的各字段,必须把字段和DB中字段同名
System.Reflection.PropertyInfo[] pps = obj.GetType().GetProperties();
//拆分成别名+列名
string[] cols = field.Split(',');
string columns = string.Empty;
foreach (string col in cols)
columns += string.Format("{0}.{1},", alias, col);
columns = columns.TrimEnd(',');
//hql
string hql = string.Format("select distinct {2} from {0} {3} {1}",
obj.GetType().ToString(),
where.ToUpper().StartsWith("WHERE") ? where : "WHERE " + where
, columns
, alias);
IList alist = HibernateTemplate.Find(hql);
IList〈T> list = new List〈T>();
if (alist != null && alist.Count > 0)
{
//是否为数组
bool isArray = (cols.Length == 1 ? false : true);
foreach (object arr in alist)
{
//产生一个类实例
T t = (T)System.Reflection.Assembly.GetAssembly(typeof(T)).CreateInstance(typeof(T).ToString());
for (int i = 0; i 〈 cols.Length; i++)
{
//逐字段检查名称
foreach (System.Reflection.PropertyInfo pi in pps)
{
if(pi.Name.Equals(cols[i]))
{
//数组与object对象
pi.SetValue(t, (isArray ? (arr as object[])[i] : arr), null);
}
}
}
list.Add(t);
}
return list;
}
else
return null;
}
catch (Exception ex)
{
ILog log = LogManager.GetLogger(typeof(T));
log.Error(ex.Message, ex);
return null;
}
}
#endregion
/// 〈summary>
/// 基于表达式的排序查询
/// 〈/summary>
/// 〈typeparam name="T">〈/typeparam>
/// 〈param name="where">〈/param>
/// 〈param name="propertyName">〈/param>
/// 〈param name="ascending">〈/param>
#region IList〈T> SearchWithOrder〈T>(string where, string propertyName, bool ascending)
public IList〈T> SearchWithOrder〈T>(string where, string propertyName, bool ascending)
{
try
{
//排序
Order order = new Order(propertyName, ascending);
//排序
ICriteria ic = Session.CreateCriteria(typeof(T));
ic.AddOrder(order);
//表达式
ICriterion exp = Expression.Sql(where);
ic.Add(exp);
return ic.List〈T>();
}
catch (Exception ex)
{
ILog log = LogManager.GetLogger(typeof(T));
log.Error(ex.Message, ex);
return null;
}
}
#endregion
/// 〈summary>
/// 执行存储过程(返回bool)
/// 〈/summary>
/// 〈param name="spName">名称〈/param>
/// 〈param name="paramInfos">参数表〈/param>
#region bool ExecuteStoredProc2(string spName, ICollection paramInfos)
public bool ExecuteStoredProc2(string spName, ICollection paramInfos)
{
bool result = true;
IDbCommand cmd = Session.Connection.CreateCommand();
cmd.CommandText = spName;
cmd.CommandType = CommandType.StoredProcedure;
// 加入参数
if (paramInfos != null)
{
foreach (ParamInfo info in paramInfos)
{
IDbDataParameter parameter = cmd.CreateParameter();
parameter.ParameterName = info.Name; // driver.FormatNameForSql( info.Name );
parameter.Value = info.Value;
cmd.Parameters.Add(parameter);
}
}
IDbConnection conn = Session.Connection;
if(conn.State == ConnectionState.Closed)
conn.Open();
try
{
cmd.Connection = conn;
IDataReader rs = cmd.ExecuteReader();
result = true;
}
catch (Exception ex)
{
ILog log = LogManager.GetLogger(typeof(DaoTemplate));
log.Error(ex.Message, ex);
result = false;
}
finally
{
Session.Connection.Close();
}
return result;
}
#endregion
/// 〈summary>
/// 执行存储过程(返回ILIST)
/// 〈/summary>
/// 〈param name="spName">名称〈/param>
/// 〈param name="paramInfos">参数表〈/param>
#region IList ExecuteStoredProc(string spName, ICollection paramInfos)
public IList ExecuteStoredProc(string spName, ICollection paramInfos)
{
IList result = new ArrayList();
IDbCommand cmd = Session.Connection.CreateCommand();
cmd.CommandText = spName;
cmd.CommandType = CommandType.StoredProcedure;
// 加入参数
if (paramInfos != null)
{
foreach (ParamInfo info in paramInfos)
{
IDbDataParameter parameter = cmd.CreateParameter();
parameter.ParameterName = info.Name; // driver.FormatNameForSql( info.Name );
parameter.Value = info.Value;
cmd.Parameters.Add(parameter);
}
}
IDbConnection conn = Session.Connection;
conn.Open();
try
{
cmd.Connection = conn;
IDataReader rs = cmd.ExecuteReader();
while (rs.Read())
{
int fieldCount = rs.FieldCount;
object[] values = new Object[fieldCount];
for (int i = 0; i 〈 fieldCount; i++)
values[i] = rs.GetValue(i);
result.Add(values);
}
}
finally
{
Session.Connection.Close();
}
return result;
}
#endregion
/// 〈summary>
/// 获取记录数
/// 〈/summary>
/// 〈typeparam name="T">〈/typeparam>
/// 〈returns>〈/returns>
#region int GetRecordCount〈T>(string where)
public int GetRecordCount〈T>(string where)
{
return GetRecordCount〈T>(where, "*");
}
#endregion
