使用 NHSessionManager 处理多个 NHibernate 程序集
本文介绍了如何配置 NHSessionManager 来使用多个 NHibernate 程序集。
引言
在 Bill McCafferty 的上一篇文章 NHibernate Best Practices with ASP.NET, Generics and Unit Tests 中,NHSessionManager
通过 App/Web 配置文件进行配置,只需与 NHibernate
核心程序集一起使用。由于 NHSessionManager
和其他程序集(Core、Data 和 Test)位于同一个解决方案中,这种简单的方式就足以满足所有实际需求。但为了代码重用,我们可以考虑将 NHibernate
实用程序类(NHSessionManager
、DomainObject
、NHGenericDao
)和接口(IGenericDao
)重新组织到一个单独的解决方案/项目中。在这种情况下,我们需要一种更通用的方式来指定 NHSessionManager
的配置。
另一篇文章 Using NHibernate with Multiple Databases 同样由 Bill McCafferty 撰写,是扩展 .NET 配置系统的很好例子。
扩展配置系统
我们需要一个配置节处理程序和配置元素规范,以便通过 App/Web 配置文件指定多个 NHibernate
程序集。
我们的目标是处理这样的配置节
<configSections>
<section name="nhibernate"
type="System.Configuration.NameValueSectionHandler,
System, Version=1.0.1.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,
log4net, Version=1.2.9.0, Culture=neutral, PublicKeyToken=b32731d11ce58905"/>
<section name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler,
Castle.Windsor"/>
<section name="nHibernateAssemblies"
type=" NHibernateSample.Common.Configuration.NHAssembliesSection,
NHibernateSample.Common"/>
</configSections>
<nHibernateAssemblies>
<NhAssemblies>
<clearAssemblies />
<NhAssembly name="Core assembly 1" assembly="ProjectName1.Core"/>
<NhAssembly name="Another core assembly" assembly="ProjectName2.Core"/>
</NhAssemblies>
</nHibernateAssemblies>
NHAssemblyElement
NHAssemblyElement
继承自 System.Configuration
命名空间中的 ConfigurationElement
。
NHAssemblyElement 类具有两个属性
Name
用于保存核心程序集的描述性名称Assembly
用于保存我们希望NHSessionManager
加载的程序集的名称
public class NHAssemblyElement : ConfigurationElement
{
public NHAssemblyElement( )
{
}
public NHAssemblyElement( string name, string assembly )
{
Name = name;
Assembly = assembly;
}
[ConfigurationProperty("name", IsRequired = true, IsKey = true,
DefaultValue = "Not Supplied")]
public string Name
{
get { return (string)this["name"]; }
set { this["name"] = value; }
}
[ConfigurationProperty("assembly", IsRequired = true, DefaultValue = "Not Supplied")]
public string Assembly
{
get { return (string)this["assembly"]; }
set { this["assembly"] = value; }
}
}
NHAssembliesCollection
NHAssembliesCollection
继承自标准 ConfigurationElementCollection
类。
[ConfigurationCollection(typeof(NHAssemblyElement))]
public class NHAssembliesCollection : ConfigurationElementCollection
{
public NHAssembliesCollection( )
{
NHAssemblyElement element = (NHAssemblyElement)CreateNewElement();
Add(element);
}
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.AddRemoveClearMap;
}
}
protected override ConfigurationElement CreateNewElement( )
{
return new NHAssemblyElement();
}
protected override object GetElementKey( ConfigurationElement element )
{
return ((NHAssemblyElement)element).Name;
}
public NHAssemblyElement this[int index]
{
get
{
return (NHAssemblyElement)BaseGet(index);
}
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
new public NHAssemblyElement this[string name]
{
get
{
return (NHAssemblyElement)BaseGet(name);
}
}
public int IndexOf( NHAssemblyElement assembly )
{
return BaseIndexOf(assembly);
}
public void Add( NHAssemblyElement assembly )
{
BaseAdd(assembly);
}
protected override void BaseAdd( ConfigurationElement element )
{
BaseAdd(element, false);
}
public void Remove( NHAssemblyElement assembly )
{
if (BaseIndexOf(assembly) >= 0)
{
BaseRemove(assembly.Name);
}
}
public void RemoveAt( int index )
{
BaseRemoveAt(index);
}
public void Remove( string name )
{
BaseRemove(name);
}
public void Clear( )
{
BaseClear();
}
}
NHAssembliesSection
NHAssembliesSection
继承自标准 ConfigurationSection
,并实现配置文件中指定的节处理程序,如下所示
<section name="nHibernateAssemblies"
type=" NHibernateSample.Common.Configuration.NHAssembliesSection,
NHibernateSample.Common"/>
代码如下:
public class NHAssembliesSection : ConfigurationSection
{
[ConfigurationProperty("NhAssemblies", IsDefaultCollection = false)]
[ConfigurationCollection(typeof(NHAssembliesCollection),
AddItemName = "NhAssembly", ClearItemsName = "clearAssemblies")]
public NHAssembliesCollection NHAssemblies
{
get
{
NHAssembliesCollection assembliesCollection =
(NHAssembliesCollection)base["NhAssemblies"];
return assembliesCollection;
}
}
}
对 NHSessionManager 的小修改
在 NHSessionManager
中,我们必须稍微修改 InitSessionFactory()
方法。
Bill McCafferty 提供的原始版本通过以下代码实现了 NHibernate
程序集的加载
private void InitSessionFactory()
{
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
// The following makes sure the web.config contains
// a declaration for the HBM_ASSEMBLY appSetting
if (ConfigurationManager.AppSettings["HBM_ASSEMBLY"] == null ||
ConfigurationManager.AppSettings["HBM_ASSEMBLY"] == "")
{
throw new ConfigurationErrorsException
("NHibernateManager.InitSessionFactory: \"HBM_ASSEMBLY\" must be " +
"provided as an appSetting within your config file. \"HBM_ASSEMBLY\"
informs NHibernate which assembly " +
"contains the HBM files. It is assumed that the HBM files are embedded resources.
An example config " +
"declaration is \" key="\" />");
}
cfg.AddAssembly(System.Configuration.ConfigurationManager.AppSettings["HBM_ASSEMBLY"]);
sessionFactory = cfg.BuildSessionFactory();
}
上面的代码处理一个配置文件,如下所示
<appSettings>
<add key="HBM_ASSEMBLY" value="NHibernateSample.Core"/>
</appSettings>
正如我在文章的介绍中提到的,使用此 NHSessionManager
实现,我们必须在每次想要处理另一个 NHibernate
程序集时更改 NHSessionManager
源代码并重新编译。
我们的替代 NHSessionManager
InitSessionFactory
实现的代码如下
private void InitSessionFactory( )
{
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
NHAssembliesSection nhAssembliesSection =
ConfigurationManager.GetSection("nHibernateAssemblies") as NHAssembliesSection;
if(nhAssembliesSection == null)
{
throw new ConfigurationErrorsException
("nHibernateAssemblies section not defined in application configuration!");
}
foreach(NHAssemblyElement element in nhAssembliesSection.NHAssemblies)
{
try
{
cfg.AddAssembly(element.Assembly);
}
catch (Exception e)
{
throw new Exception(" Can not add assembly! " + e.Message, e.InnerException);
}
}
try
{
sessionFactory = cfg.BuildSessionFactory();
}
catch (Exception e)
{
throw new Exception(" Can not create session factory! " +
e.Message, e.InnerException);
}
}
历史
- 2007 年 2 月 1 日:初始发布