Learing NHibernate 1st
一. 准备工作
1.下载最新版本的NHibernate, 本文使用的是NHibernate-3.3.3, 下载地址为http://nhforge.org/
2.新建一个控制台应用程序, 命名为ConsoleApp
3.引用添加NHibernate程序集, 该程序集位于解压文件夹的Required_Bins下面
二. 配置NHibernate
1.在ConsoleApp程序中新建一个xml文件, 并命名为hibernate.cfg.xml(注意名称一定要一致)
2.为xml文件新增架构schema, 添加nhibernate-configuration.xsd的引用, 该文件同样位于解压文件夹的Required_Bins目录下(使用架构, 可以启用xml智能提示功能, 为编写配置文件带来便利)
3.在xml文件中写入配置信息, 本机使用的是SqlServer 2008, 写法如下:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property> <property name="connection.connection_string">Server=home-pc\SQLEXPRESS;Database = Test;Integrated Security=True</property> <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property> <mapping assembly="ConsoleApp"/> </session-factory> </hibernate-configuration>
hibernate-configuration是根节点, xmlns是xml namespace的缩写, 作为一个标识作用, 避免相同名称的标签使用歧义.
session-factory是表示会话工厂的节点.
"connection.driver_class"的property表示使用哪个数据库驱动类. 这里的"NHibernate.Driver.SqlClientDriver"其实就是一个真实存在的类, 用ILSpy查看NHibernate程序集, 可以看到SqlClientDriver封装了操作SqlServer的ADO.NET对象.
"connection.connection_string"property的作用是存储数据库连接字符串.
"dialect"中文翻译为方言的意思, 这是由于即使是SqlServer, 不同版本的SqlServer会存在一些差异, 主要包括数据类型和sql语句编写的不同. 同样这里的"NHibernate.Dialect.MsSql2008Dialect"也是一个类.
mapping是表示程序集的名称, NHibernate会搜索这个命名空间下为嵌入的资源且命名结尾为.hbm.xml的文件.
4.把hibernate.cfg.xml文件的属性复制到输出目录设置为始终复制, 这样该文件就会自动发布到bin文件夹下.
三. 测试NHibernate是否配置成功
1.在SqlServer中创建一个新的数据库, 命名为Test
2.在ConsoleApp的Program.cs加上using NHibernate; 和 using NHibernate.Cfg;
3.在static void Main(string args[])中写上如下代码:
ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
4.运行程序, 如果程序没有出错的话, 恭喜, 你的NHibernate配置成功了!
四. NHibernate创建SessionFactory的执行过程
接下来根据NHibernate的源码, 来探讨一下创建SessionFactory的过程究竟执行了什么操作.
//Part 1 public Configuration() : this(new SettingsFactory()) { } //Part 1.1 protected Configuration(SettingsFactory settingsFactory) { this.InitBlock(); this.settingsFactory = settingsFactory; this.Reset(); } //Part 1.1.1 private void InitBlock() { this.mapping = this.BuildMapping(); } //Part 1.1.1.1 public virtual IMapping BuildMapping() { return new Configuration.Mapping(this); } //Part 1.1.2 protected void Reset() { this.classes = new Dictionary<string, PersistentClass>(); this.Imports = new Dictionary<string, string>(); this.collections = new Dictionary<string, Collection>(); this.tables = new Dictionary<string, Table>(); this.NamedQueries = new Dictionary<string, NamedQueryDefinition>(); this.NamedSQLQueries = new Dictionary<string, NamedSQLQueryDefinition>(); this.SqlResultSetMappings = new Dictionary<string, ResultSetMappingDefinition>(); this.secondPasses = new List<SecondPassCommand>(); this.propertyReferences = new List<Mappings.PropertyReference>(); this.FilterDefinitions = new Dictionary<string, FilterDefinition>(); this.interceptor = Configuration.emptyInterceptor; this.properties = Environment.Properties; this.auxiliaryDatabaseObjects = new List<IAuxiliaryDatabaseObject>(); this.SqlFunctions = new Dictionary<string, ISQLFunction>(); this.mappingsQueue = new MappingsQueue(); this.eventListeners = new EventListeners(); this.typeDefs = new Dictionary<string, TypeDef>(); this.extendsQueue = new HashedSet<ExtendsQueueEntry>(); this.tableNameBinding = new Dictionary<string, Mappings.TableDescription>(); this.columnNameBindingPerTable = new Dictionary<Table, Mappings.ColumnNames>(); this.filtersSecondPasses = new Queue<FilterSecondPassArgs>(); }
可以看到new Configuration() 一直在实例化一些对象, 并没有执行其他有关加载配置信息的操作.
//Part 2 public Configuration Configure() { IHibernateConfiguration hc = ConfigurationManager.GetSection("hibernate-configuration") as IHibernateConfiguration; if (hc != null && hc.SessionFactory != null) { return this.DoConfigure(hc.SessionFactory); } return this.Configure(this.GetDefaultConfigurationFilePath()); }
这里先从系统的配置文件中读取“hibernate-configuration”节点, 如果系统配置文件不存在这个节点的话, 再调用this.Configure(this.GetDefaultConfigurationFilePath())执行配置.
//Part 2.1 protected virtual string GetDefaultConfigurationFilePath() { string baseDir = AppDomain.CurrentDomain.BaseDirectory; string searchPath = AppDomain.CurrentDomain.RelativeSearchPath ?? string.Empty; string relativeSearchPath = searchPath.Split(new char[] { ';' }).First<string>(); string binPath = Path.Combine(baseDir, relativeSearchPath); return Path.Combine(binPath, "hibernate.cfg.xml"); }
//Part 2.2 public Configuration Configure(string fileName) { return this.Configure(fileName, false); } //Part 2.2.1 private Configuration Configure(string fileName, bool ignoreSessionFactoryConfig) { if (ignoreSessionFactoryConfig) { Environment.ResetSessionFactoryProperties(); this.properties = Environment.Properties; } XmlTextReader reader = null; Configuration result; try { reader = new XmlTextReader(fileName); result = this.Configure(reader); } finally { if (reader != null) { reader.Close(); } } return result; } //Part 2.2.1.1 public Configuration Configure(XmlReader textReader) { if (textReader == null) { throw new HibernateConfigException("Could not configure NHibernate.", new ArgumentException("A null value was passed in.", "textReader")); } Configuration result; try { IHibernateConfiguration hc = new HibernateConfiguration(textReader); result = this.DoConfigure(hc.SessionFactory); } catch (Exception e) { Configuration.log.Error("Problem parsing configuration", e); throw; } return result; }
//Part 2.2.1.1.1 public HibernateConfiguration(XmlReader hbConfigurationReader) : this(hbConfigurationReader, false) { } private HibernateConfiguration(XmlReader hbConfigurationReader, bool fromAppSetting) { XPathNavigator nav; try { nav = new XPathDocument(XmlReader.Create(hbConfigurationReader, this.GetSettings())).CreateNavigator(); } catch (HibernateConfigException) { throw; } catch (Exception e) { throw new HibernateConfigException(e); } this.Parse(nav, fromAppSetting); } private void Parse(XPathNavigator navigator, bool fromAppConfig) { this.ParseByteCodeProvider(navigator, fromAppConfig); this.ParseReflectionOptimizer(navigator, fromAppConfig); XPathNavigator xpn = navigator.SelectSingleNode(CfgXmlHelper.SessionFactoryExpression); if (xpn != null) { this.sessionFactory = new SessionFactoryConfiguration(navigator); return; } if (!fromAppConfig) { throw new HibernateConfigException("<session-factory xmlns='urn:nhibernate-configuration-2.2'> element was not found in the configuration file."); } } internal SessionFactoryConfiguration(XPathNavigator hbConfigurationSection) { if (hbConfigurationSection == null) { throw new ArgumentNullException("hbConfigurationSection"); } this.Parse(hbConfigurationSection); } private void Parse(XPathNavigator navigator) { this.ParseName(navigator); this.ParseProperties(navigator); this.ParseMappings(navigator); this.ParseClassesCache(navigator); this.ParseCollectionsCache(navigator); this.ParseListeners(navigator); this.ParseEvents(navigator); } /* *这里一直在读取配置文件中的session-factory下的节点所代表的信息 *property, mapping, class-cache, collection-cache, listener, event都可以在session-factory下配置 */
// NHibernate.Cfg.Configuration protected Configuration DoConfigure(ISessionFactoryConfiguration factoryConfiguration) { if (!string.IsNullOrEmpty(factoryConfiguration.Name)) { this.properties["session_factory_name"] = factoryConfiguration.Name; } this.AddProperties(factoryConfiguration); foreach (MappingConfiguration mc in factoryConfiguration.Mappings) { if (mc.IsEmpty()) { throw new HibernateConfigException("<mapping> element in configuration specifies no attributes"); } if (!string.IsNullOrEmpty(mc.Resource) && !string.IsNullOrEmpty(mc.Assembly)) { Configuration.log.Debug(string.Concat(new string[] { factoryConfiguration.Name, "<-", mc.Resource, " in ", mc.Assembly })); this.AddResource(mc.Resource, Assembly.Load(mc.Assembly)); } else { if (!string.IsNullOrEmpty(mc.Assembly)) { Configuration.log.Debug(factoryConfiguration.Name + "<-" + mc.Assembly); this.AddAssembly(mc.Assembly); } else { if (!string.IsNullOrEmpty(mc.File)) { Configuration.log.Debug(factoryConfiguration.Name + "<-" + mc.File); this.AddFile(mc.File); } } } } foreach (ClassCacheConfiguration ccc in factoryConfiguration.ClassesCache) { string region = string.IsNullOrEmpty(ccc.Region) ? ccc.Class : ccc.Region; bool includeLazy = ccc.Include != ClassCacheInclude.NonLazy; this.SetCacheConcurrencyStrategy(ccc.Class, EntityCacheUsageParser.ToString(ccc.Usage), region, includeLazy); } foreach (CollectionCacheConfiguration ccc2 in factoryConfiguration.CollectionsCache) { string role = ccc2.Collection; if (this.GetCollectionMapping(role) == null) { throw new HibernateConfigException("collection-cache Configuration: Cannot configure cache for unknown collection role " + role); } string region2 = string.IsNullOrEmpty(ccc2.Region) ? role : ccc2.Region; this.SetCollectionCacheConcurrencyStrategy(role, EntityCacheUsageParser.ToString(ccc2.Usage), region2); } foreach (EventConfiguration ec in factoryConfiguration.Events) { string[] listenerClasses = new string[ec.Listeners.Count]; for (int i = 0; i < ec.Listeners.Count; i++) { listenerClasses[i] = ec.Listeners[i].Class; } Configuration.log.Debug(string.Concat(new object[] { "Event listeners: ", ec.Type, "=", StringHelper.ToString(listenerClasses) })); this.SetListeners(ec.Type, listenerClasses); } foreach (ListenerConfiguration lc in factoryConfiguration.Listeners) { Configuration.log.Debug(string.Concat(new object[] { "Event listener: ", lc.Type, "=", lc.Class })); this.SetListeners(lc.Type, new string[] { lc.Class }); } if (!string.IsNullOrEmpty(factoryConfiguration.Name)) { Configuration.log.Info("Configured SessionFactory: " + factoryConfiguration.Name); } Configuration.log.Debug("properties: " + this.properties); return this; }
//Part 2.3 public ISessionFactory BuildSessionFactory() { this.ConfigureProxyFactoryFactory(); this.SecondPassCompile(); this.Validate(); Environment.VerifyProperties(this.properties); Settings settings = this.BuildSettings(); this.Schemas = null; return new SessionFactoryImpl(this, this.mapping, settings, this.GetInitializedEventListeners()); }
总结: 整个执行过程主要包括加载配置文件的信息, 加载对象的hbm.xml匹配信息, 反射对应的实体类的信息, 所以创建SessionFactory的过程开销很大, 应用程序启动的时候应该只执行一次创建SessionFactory的操作.

浙公网安备 33010602011771号