NHibernate 是一个基于.docx
《NHibernate 是一个基于.docx》由会员分享,可在线阅读,更多相关《NHibernate 是一个基于.docx(35页珍藏版)》请在冰豆网上搜索。
NHibernate是一个基于
Nhibernate全面分析
NHibernate是一个基于.Net的针对关系型数据库的对象持久化类库.Nhibernate来源于非常优秀的基于Java的Hibernate关系型持久化工具.NHibernate源码分析之开篇:
计划和安排只从使用NHibernate以来,请被其强大的功能和使用的简洁所吸引.为了进一步研究NHibernate,决定分析其源代码,如有感兴趣者,欢迎一起研究.这里列出了将要分析的部分:
官方源码下载地址:
NHibernate配置和持久对象映射文件NHibernate配置有三种方式来存放nhibernate的配置
1,作为单独的一节放在相应程序的配置文件中,对于执行文件或类库为文件名称后加.config,对于则是放在web.config中.这种方式必须在配置文件的configSetions中声明nhibernate的配置节,配置内容由Cfg.Environment类来读取,该类所有成员均为静态的,另外它还定义了配置中key值的常数.
2.放在一个单独的配置文件中,默认为hibernate.cfg.xml,使用时必须调用Cfg.Configuration.Config().如不是默认的配置文件名,还必须指明配置文件名称.这种方式最适合多数据库的情况,可以为每个数据库建立一个配置文件.
3.手工在程序中加入,配置内容最后将加入到Cfg.Configuration.Properties属性中,此属性为一IDictionary对象,并且为public,其余的就不用多话了吧.下面对几个重要的key值说明一下:
hibernate.connection.provider连接提供者,取值必须是实现了IConnectionProvider接口的类的全名,当前版本只能取值NHibernate.Connection.DriverConnectionProvider;hibernate.connection.driver_class数据驱动类,取值必须是实现了IDriver接口的类的全名,常用的选择有NHibernate.Driver.SqlClientDriver,NHibernate.Driver.OleDbDriver等;hibernate.dialect数据库方言,取值必须是继承之Dialect的类的全名,最常用的就是NHibernate.Dialect.MsSql2000Dialect了,其它的没用过,不清楚能不能正常使用;hibernate.connection.connection_string连接字符串,取值与driver_class对应即可;hibernate.show_sql指明是否在log4net日志中显示sql语句,主要用于调试,取值为true或false;完整的配置key列表请查看Cfg.Environment类中的常数声明.持久对象映射文件nhibernate为我们提供了很多方式将持久对象映射文件加入到Cfg.Configuration类,下面将其一一列出:
AddXmlFile:
加入包括对象映射信息的文件;AddXmlString:
加入包含映射信息的字符串;AddDocument:
加入包含映射信息的Xmldocument;AddInputStream:
加入包含映射信息的输入流;AddXmlReader:
加入包含映射信息的XmlReader;AddResource:
加入指定程序集的映射信息资源;AddClass:
加入以类名指定的映射信息资源,映射文件必须为classname.hbm.xml;AddAssembly:
加入指定程序集名称的映射信息资源注意:
如果映射信息为文件形式,包括加入到程序集资源的文件,那么文件名必须以.hbm.xml结尾.NHibernate架构分析uml图从图中可以看到,Session和SessionFactory是NHibernate的核心部分.SessionFactory维护到持久机制(数据库)的连接并对它们进行管理,同时还保存着所有持久对象的映射信息.SessionFactory由Configuration.BuildSessionFactory创建,这个对象一般使用Singleton模式.Session用于将对象持久化,支持数据库事务,另外Session还提供了强大的数据加载功能.Session由SessionFactory创建.其它对象说明:
IConnectionProvider:
连接提供者接口,负责与数据进行连接;Dialect:
数据库方言;CollectionPersister:
集合持久化类;IClassPersister:
类持久化接口,定义了基本的CRUD操作;TransactionFactory:
数据库事务工厂;IInterceptor:
拦截器接口,用于在操作执行时进行一些处理,典型的就是记录操作日志;NHibernate源码分析之一:
配置信息配置信息用于指定NH以何种方式访问数据库,根据这些配置信息,NH动态的创建数据访问对象并与数据库进行交互.除了.net类库自带的Odbc,OleDb,OracleClient和SqlClient访问方式外,在0.2版中,NH增加了用于访问MySQL和Firebird的访问方式,这两种访问方式由第三方组件提供,mono的用户应该高兴了.:
)NH的配置有两种存放方式存放在应用程序集的配置文件中,对于Web应用程序则存放在Web.config中.这种方式必须指定配置节的处理程序(类);存放在一个单独的xml文件中,使用这种方式我们必须在程序中显式的加载配置文件,本文后面有详细说明.此方式有一个优点,就是在多数据库的情况下,可以用不同的配置文件与各个数据库进行对应.配置内容先来看看配置内容,下列是一个简单的配置例子:
连接提供者,取值必须是实现了IConnectionProvider接口的类的全名,当前版本只能取值NHibernate.Connection.DriverConnectionProvider.数据库方言,取值必须是继承之Dialect的类的全名,最常用的就是NHibernate.Dialect.MsSql2000Dialect了吧,谁让它是M$的了.数据驱动类,取值必须是实现了IDriver接口的类的全名,常用的选择有NHibernate.Driver.SqlClientDriver,NHibernate.Driver.OleDbDriver等,不过现在又多了ByteFXDataDriver(访问MySQL).连接字符串,取值要与driver_class指定的数据驱动类对应.配置节处理程序因为NH的配置信息为自定义配置节,所以必须指定配置节处理程序,NH的配置内容采用key/value形式,这和预定义配置节appSettings是一样的,我们只要用.net内置的配置节处理程序就可以处理NH的配置内容了,这个处理key/value形式的类就是NameValueSetionHandler.nhibernate配置节的声明如下:
注意Version的值对于不同的.netframework版本取值也可能不一样.在nh中,Environment类用于读取配置信息,代码如下//***Environment.cs-65行***staticEnvironment(){NameValueCollectionprops=System.Configuration.ConfigurationSettings.GetConfig("nhibernate")asNameValueCollection;if(props==null){return;}foreach(stringkeyinprops.Keys){properties[key]=props[key];}}这是一个静态构造函数,在静态成员首次调用时执行.配置信息放在properties集合中.//***Environment.cs-90行***publicstaticIDictionaryProperties{get{IDictionarycopy=newHashtable(properties.Count);foreach(DictionaryEntrydeinproperties){copy[de.Key]=de.Value;}returncopy;}}Properties属性用于访问配置信息,注意这里并没有直接返回properties,而是复制了一个集合用于返回.曾有网友问为什么不是直接返回properties可能的原因是如果返回properties(即引用)话,那么配置信息将是共享的,如果在程序中修改了properties,那么将影响到其它地方.另外Environment类中还定义了一些属性名称常数.在程序中操作配置信息除了在配置文件中指定nh的配置信息外,nh还允许我们在程序中操作配置信息,这对于一些敏感的数据,如数据库连接串,提供了一种安全的操作方法(可以在程序中加入连接串属性,而不用将其存储在配置文件中).Configuration类提供提供两个方法和一个属性用于操作配置信息.//***Configuration.cs-637行***publicConfigurationAddProperties(IDictionaryproperties){foreach(DictionaryEntrydeinproperties){this.properties.Add(de.Key,de.Value);}returnthis;}将一个数据字典对象加入到配置属性中.//***Configuration.cs-646行***publicConfigurationSetProperty(stringname,stringvalue){properties[name]=value;returnthis;}设置指定的属性的值,name应使用Environment类中定义的那些属性名称常数.//***Configuration.cs-625行***publicIDictionaryProperties{get{returnproperties;}set{this.properties=value;}}这个就不用多说的吧,用dotNet的人都知道.有了Properties,想干啥就干啥吧:
-)NHibernate源码分析之一续:
对象映射1.持久对象映射文件关于持久对象映射文件,这里就不多说了,可参考nhibernate的例子和文档.在nhibernate源代码的根目录里有一个nhibernate-mapping-2.0.xsd文档,这个文档是nhibernate用来对映射文件进行验证的,我们也可以借助相关软件用这个文档来验证映射文件的有效性.2.映射信息的读取通过Configuration类,可以用多种方式读取映射信息,一些以Add开头的方法就是用来加入映射信息的,这些方法最终将调用Add(XmlDocumentdoc).//**Configuration.cs**privateHashtableclasses=newHashtable();classes集合用于存放所有的持久对象映射信息,它的Key为持久类的类型;Value为PermissionClass类的子类.privatevoidAdd(XmlDocumentdoc){try{Binder.dialect=Dialect.Dialect.GetDialect(properties);Binder.BindRoot(doc,CreateMappings());}catch(MappingExceptionme){log.Error("Couldnotcompilethemappingdocument",me);throwme;}//endtry/catch}AddDocument方法调用Binder的静态方法BindRoot来绑定持久类映射信息.CreateMappings返回一个Mappings对象,此对象是一个简单封装了所有映射信息集合的类.3.建立对象映射信息Binder类的BindRoot用于绑定映射信息中的所有映射内容.//**Binder.cs**publicstaticvoidBindRoot(XmlDocumentdoc,Mappingsmodel){//...foreach(XmlNodeninhmNode.SelectNodes(nsPrefix+":
class",nsmgr)){RootClassrootclass=newRootClass();Binder.BindRootClass(n,rootclass,model);model.AddClass(rootclass);}//...}遍历所有的类映射节点,然后调用BindRootClass来绑定类映射信息,最后将类映射信息加到集合中.其中RootClass为PermissionClass的子类.publicstaticvoidBindRootClass(XmlNodenode,RootClassmodel,Mappingsmappings){BindClass(node,model,mappings);//TABLENAMEXmlAttributetableNameNode=node.Attributes["table"];stringtableName=(tableNameNode==null)StringHelper.Unqualify(model.PersistentClazz.Name):
tableNameNode.Value;XmlAttributeschemaNode=node.Attributes["schema"];stringschema=schemaNode==nullmappings.SchemaName:
schemaNode.Value;Tabletable=mappings.AddTable(schema,tableName);model.Table=table;//...PropertiesFromXML(node,model,mappings);}BindRootClass首先调用BindClass绑定持久类映射信息,然后调用PropertiesFromXML来绑定类属性.publicstaticvoidBindClass(XmlNodenode,PersistentClassmodel,Mappingsmapping){stringclassName=node.Attributes["name"]==nullnull:
node.Attributes["name"].Value;//classtry{model.PersistentClazz=ReflectHelper.ClassForName(className);}catch(Exceptioncnfe){thrownewMappingException("persistentclassnotfound",cnfe);}//...}BindClass通过反射来取得持久对象的类型.protectedstaticvoidPropertiesFromXML(XmlNodenode,PersistentClassmodel,Mappingsmappings){stringpath=model.Name;Tabletable=model.Table;foreach(XmlNodesubnodeinnode.ChildNodes){CollectionTypecollectType=CollectionType.CollectionTypeFromString(name);Valuevalue=null;if(collectType!
=null){value=newValue(table);BindValue(subnode,value,true);}elseif("many-to-one".Equals(name)){value=newManyToOne(table);BindManyToOne(subnode,(ManyToOne)value,propertyName,true);}elseif("any".Equals(name)){value=newAny(table);BindAny(subnode,(Any)value,true);}elseif("one-to-one".Equals(name)){value=newOneToOne(table,model.Identifier);BindOneToOne(subnode,(OneToOne)value,true);}elseif("property".Equals(name)){value=newValue(table);BindValue(subnode,value,true,propertyName);}elseif("component".Equals(name)){value=newComponent(model);BindComponent(subnode,(Component)value,reflectedClass,subpath,true,mappings);}elseif("subclass".Equals(name)){Subclasssubclass=newSubclass(model);BindSubclass(subnode,subclass,mappings);}elseif("joined-subclass".Equals(name)){Subclasssubclass=newSubclass(model);BindJoinedSubclass(subnode,subclass,mappings);}if(value!
=null){Propertyprop=newProperty(value);BindProperty(subnode,prop,mappings);}}}遍历所有子节点,然后根据节点类型对进行绑定.(注:
部分内容已删除)关于属性的映射以后有空再详细研究,只需要知道属性已加入到RootClass的Properties属性就行了.NHibernate源码分析之二:
会话工厂会话工厂是NHibernate中的关键类,它与数据库连接,数据库事务等进行交互,还存储着与所有持久对象类型关联的持久化对象,持久化类是持久化的关键,它实现基本的CRUD操作.当用户需要持久操作时,由会话工厂创建一个会话供用户进行持久操作.1.会话工厂的创建会话工厂由ISessionFactory接口实现,由Configuration的BuildSessionFactory方法创建,会话工厂应该使用Singleton模式.如果要访问多个数据库,应建立多个会话工厂.//***Configuration.cs***publicISessionFactoryBuildSessionFactory(){//...Hashtablecopy=newHashtable();foreach(DictionaryEntrydeinproperties){copy.Add(de.Key,de.Value);}returnnewSessionFactoryImpl(this,copy,interceptor);}其中SessionFactoryImpl为实现ISessionFactory的类,这个类的修饰为Internal.2.持久化类的创建持久化类用于对持久对象进行持久化操作,每一个持久对象类型都有一个与之关联的持久化对象.持久化类继承自IClassPersister接口,这个接口定义了用于持久对象的CRUD操作.//***SessionFactoryImpl***privateIDictionaryclassPersisters;持久化对象集合,Key为持久对象的类型;privateIDictionaryclassPersistersByName;持久化对象集合,Key为持久对象的类名;publicSessionFactoryImpl(Configurationcfg,IDictionaryproperties,IInterceptorinterceptor){//...foreach(PersistentClassmodelincfg.ClassMappings){System.TypepersisterClass=model.Persister;IClassPersistercp;//TODO:
H2.0.3createdaPersisterFactoryif(persisterClass==null||persisterClass==typeof(EntityPersister)){cp=newEntityPersister(model,this);}elseif(persisterClass==typeof(NormalizedEntityPersister)){cp=newNormalizedEntityPersister(model,this);}else{cp=InstantiatePersister(persisterClass,model);}classPersisters[model.PersistentClazz]=cp;classPersistersByName[model.Name]=cp;}//...}在构造函数中遍历所有持久类映射信息,然后根据持久类的持久类型建立一个持久化对象,并将此对象加入到集合中.InstantiatePersister用于创建一个自定义的持久化对象,类名称由映射文件中Class节点的Persister属性指定,自定义持久化类必须实现IClassPersister接口.3.连接提供者连接提供者由IConnectionProvider接口实现,会话工厂通过连接提供者与持久机制(数据库等)进行交互,例如取得数据库连接等.//***SessionFactoryImpl.cs***publicSessionFac