场景:
使用Nunit测试一个使用NHibernate的项目,被测试的项目为Job.Personal.Core,测试项目为Job.Personal.Tests。
配置:
1、在主项目中添加对NHibernate.dll的引用,这样同时会关联到Castle.DynamicProxy.dll HashCodeProvider.dll Iesi.Collections.dll 如果需要记录异常日志的则再引用log4net.dll
2、在测试项目中添加对NHibernate.dll的引用。
3、因为测试项目是使用Nunit进行测试,同时这是一个组件项目,所以配置文件要存放在bin/Debug中,命名为:Job.Personal.Tests.dll.config
4、为定位hbm.xml文件,把对该xml文件的生成操作修改为嵌入的资源。
5、编辑Job.Personal.Tests.dll.config配置文件。
<?
xml version="1.0" encoding="utf-8"
?>
<
configuration
>
<
configSections
>
<
section
name
="nhibernate"
type
="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</
configSections
>
<
nhibernate
>
<
add
key
="hibernate.connection.provider"
value
="NHibernate.Connection.DriverConnectionProvider"
/>
<
add
key
="hibernate.dialect"
value
="NHibernate.Dialect.MsSql2000Dialect"
/>
<
add
key
="hibernate.connection.driver_class"
value
="NHibernate.Driver.SqlClientDriver"
/>
<
add
key
="hibernate.connection.connection_string"
value
="server=(local); database=NHBDemo; uid=sa; pwd=007520;"
/>
</
nhibernate
>
</
configuration
>
6、编辑MyJob.hbm.xml
<?
xml version="1.0" encoding="utf-8"
?>
<
hibernate-mapping
xmlns
="urn:nhibernate-mapping-2.0"
>
<
class
name
="Job.Personal.Core.Domain.MyJob, Job.Personal.Core"
table
="Job_Job"
>
<
id
name
="ID"
column
="ID"
type
="Int32"
unsaved-value
="-1"
>
<
generator
class
="native"
/>
</
id
>
<
property
name
="Guid"
type
="Guid"
column
="Guid"
/>
<
property
name
="EnterpriseGuid"
type
="Guid"
column
="EnterpriseGuid"
/>
<
property
name
="Name"
type
="String(50)"
column
="Name"
/>
<
property
name
="Description"
type
="String(4000)"
column
="Description"
/>
</
class
>
</
hibernate-mapping
>
注意:主键的类名必须为ID,如果主键是由数据库自动生成的,则使用<generator class="native" />声明,而不是用<generator class="assigned" />
7、如果使用编辑hbm.xml时使用智能感知,则拷入nhibernate-configuration-2.0.xsd nhibernate-generic.xsd nhibernate-mapping-2.0.xsd文件到hbm.xml所在目录。
8、对于由hbm.xml生成业务对象的操作,则能通过NHibernateContrib,这个在以后的随笔中讲解。现在我们就有了一个对应于hbm.xml的业务对象了。
9、为操作的封装性,这里我提取了Cuyahoga项目对Session的操作,如下:
SessionFactory.cs
using
System;
using
System.Reflection;
using
NHibernate;
using
NHibernate.Cfg;
namespace
Job.Personal.Core.Service
{
/**//// <summary>
/// SessionFactory 提供 NHibernate sessions
/// </summary>
public class SessionFactory
{
private static SessionFactory _sessionFactory = new SessionFactory();
private Configuration _nhibernateConfiguration;
private ISessionFactory _nhibernateFactory;
private bool _classesAdded = false;
protected SessionFactory()
{
RegisterCoreClasses();
}
public static SessionFactory GetInstance()
{
return _sessionFactory;
}
/**//// <summary>
/// 返回当前的NHibernate ISessionFactory
/// </summary>
public ISessionFactory GetNHibernateFactory()
{
return this._nhibernateFactory;
}
/**//// <summary>
/// 获取一个新的NHibernate session
/// </summary>
public ISession GetSession()
{
return this._nhibernateFactory.OpenSession();
}
/**//// <summary>
/// 添加一个类到NHibernate mappings 如果类已经被映射,则什么也不做
/// </summary>
public void RegisterPersistentClass(Type type)
{
if (this._nhibernateConfiguration.GetClassMapping(type) == null)
{
// Class isn't mapped yet, so do it now.
this._nhibernateConfiguration.AddClass(type);
this._classesAdded = true;
}
}
/**//// <summary>
/// 重新构建一个NHibernate ISessionFactory,在注册一个新类后使用它。
/// </summary>
public bool Rebuild()
{
// Rebuild NHibernate SessionFactory to activate the new mapping.
if (this._classesAdded)
{
this._nhibernateFactory = this._nhibernateConfiguration.BuildSessionFactory();
this._classesAdded = false;
return true;
}
else
{
return false;
}
}
private void RegisterCoreClasses()
{
Configuration config = new Configuration();
this._nhibernateConfiguration = config.AddAssembly(this.GetType().Assembly); //传入本组件Job.Personal.Core
this._nhibernateFactory = this._nhibernateConfiguration.BuildSessionFactory();//
}
}
}
CoreRepository.cs
using
System;
using
System.Collections;
using
System.Reflection;
using
log4net;
using
NHibernate;
using
NHibernate.Expression;
using
Job.Personal.Core.Domain;
namespace
Job.Personal.Core.Service
{
/**//// <summary>
/// CoreRepository 的摘要说明。
/// </summary>
public class CoreRepository
{
private static readonly ILog log = LogManager.GetLogger(typeof(CoreRepository));
private ISessionFactory _factory;
private ISession _activeSession;
/**//// <summary>
/// 获取当前活跃的NHibernate session
/// </summary>
public ISession ActiveSession
{
get { return _activeSession; }
}
public CoreRepository() : this(false)
{
}
/**//// <summary>
/// 为核心对象创建一个库贮藏
/// </summary>
/// <param name="openSession">指示CoreRepository是否应该打开一个session并保存到内存中</param>
public CoreRepository(bool openSession)
{
this._factory = SessionFactory.GetInstance().GetNHibernateFactory();
if (openSession)
{
this._activeSession = this._factory.OpenSession();
}
}
/**//// <summary>
/// 打开一个NHibernate session
/// </summary>
public void OpenSession()
{
if (this._activeSession == null || ! this._activeSession.IsOpen)
{
this._activeSession = this._factory.OpenSession();
}
else
{
throw new InvalidOperationException("The repository already has an open session");
}
}
/**//// <summary>
/// Flushes the current active NHibernate session.
/// </summary>
public void FlushSession()
{
if (this._activeSession != null && this._activeSession.IsOpen)
{
this._activeSession.Flush();
}
}
/**//// <summary>
/// Close the active NHibernate session
/// </summary>
public void CloseSession()
{
if (this._activeSession != null)
{
if (this._activeSession.IsOpen)
{
this._activeSession.Close();
}
this._activeSession.Dispose();
}
}
Generic methods#region Generic methods
/**//// <summary>
/// Generic method for retrieving single objects by primary key.
/// </summary>
/// <param name="type">The type of the object to fetch.</param>
/// <param name="id">The identifier of the object.</param>
/// <returns></returns>
public object GetObjectById(Type type, int id)
{
if (this._activeSession != null)
{
return this._activeSession.Load(type, id);
}
else
{
throw new NullReferenceException("The repository doesn't have an active session");
}
}
/**//// <summary>
/// Generic method for retrieving single objects by primary key.
/// </summary>
/// <param name="type">The type of the object to fetch.</param>
/// <param name="id">The identifier of the object.</param>
/// <param name="allowNull">Allow null as return value.</param>
/// <returns></returns>
public object GetObjectById(Type type, int id, bool allowNull)
{
if (allowNull)
{
if (this._activeSession != null)
{
return this._activeSession.Get(type, id);
}
else
{
throw new NullReferenceException("The repository doesn't have an active session");
}
}
else
{
return GetObjectById(type, id);
}
}
/**//// <summary>
/// Get all objects of a given type.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public IList GetAll(Type type)
{
return GetAll(type, null);
}
/**//// <summary>
/// Get all objects of a given type and add one or more names of properties to sort on.
/// </summary>
/// <param name="type"></param>
/// <param name="sortProperties"></param>
/// <remarks>Sorting is Ascending order. Construct a specific query/method when the sort order
/// should be different.</remarks>
/// <returns></returns>
public IList GetAll(Type type, params string[] sortProperties)
{
ICriteria crit = this._activeSession.CreateCriteria(type);
if (sortProperties != null)
{
foreach (string sortProperty in sortProperties)
{
crit.AddOrder(Order.Asc(sortProperty));
}
}
return crit.List();
}
/**//// <summary>
/// Generic method to insert an object.
/// </summary>
/// <param name="obj"></param>
public void SaveObject(object obj)
{
ITransaction trn = this._activeSession.BeginTransaction();
try
{
// Try to find a UpdateTimestamp property and when found, set it to the current date/time.
PropertyInfo pi = obj.GetType().GetProperty("UpdateTimestamp");//TODO:UpdateTimestamp?????
if (pi != null)
{
pi.SetValue(obj, DateTime.Now, null);
}
this._activeSession.Save(obj);
trn.Commit();
}
catch (Exception ex)
{
trn.Rollback();
throw ex;
}
}
/**//// <summary>
/// Generic method to update an object.
/// </summary>
/// <param name="obj"></param>
public void UpdateObject(object obj)
{
ITransaction trn = this._activeSession.BeginTransaction();
try
{
this._activeSession.Update(obj);
trn.Commit();
}
catch (Exception ex)
{
trn.Rollback();
throw ex;
}
}
/**//// <summary>
/// Delete a specific object. Settings in the mapping file determine if this cascades
/// to related objects.
/// </summary>
/// <param name="obj"></param>
public void DeleteObject(object obj)
{
ITransaction trn = this._activeSession.BeginTransaction();
try
{
this._activeSession.Delete(obj);
trn.Commit();
}
catch (Exception ex)
{
trn.Rollback();
throw ex;
}
}
/**//// <summary>
/// Mark an object for deletion. Commit the deletion with Session.Flush.
/// </summary>
/// <param name="obj"></param>
public void MarkForDeletion(object obj)
{
this._activeSession.Delete(obj);
}
/**//// <summary>
/// Clear the cache for a given type.
/// </summary>
/// <param name="type"></param>
public void ClearCache(Type type)
{
log.Info("Clearing cache for type " + type.Name);
this._factory.Evict(type);
}
/**//// <summary>
/// Clear the cache for a given collection.
/// </summary>
/// <param name="roleName">The full path to a collection property,
/// for example Cuyahoga.Core.Domain.Node.Sections.</param>
public void ClearCollectionCache(string roleName)
{
log.Info("Clearing cache for collection property " + roleName);
this._factory.EvictCollection(roleName);
}
/**//// <summary>
/// Clear the cache for a given cacheRegion.
/// </summary>
/// <param name="cacheRegion"></param>
public void ClearQueryCache(string cacheRegion)
{
log.Info("Clearing query cache for cacheregion " + cacheRegion);
this._factory.EvictQueries(cacheRegion);
}
#endregion
}
}
8、在Job.Personal.Tests项目中添加ProxyTest测试类。
using
System;
using
NUnit.Framework;
using
NHibernate;
using
NHibernate.Cfg;
using
Job.Personal.Core.Domain;
using
Job.Personal.Core.Service;
namespace
Job.Personal.Tests
{
[TestFixture]
public class ProxyTest
{
public ProxyTest(){}
[Test]
public void ProxyTestTemplate()
{
CoreRepository cr = new CoreRepository(true);
MyJob job = new MyJob();
job.Guid = Guid.NewGuid();
job.EnterpriseGuid = Guid.NewGuid();
job.Name = "测试";
cr.SaveObject(job);
}
}
}