一、NHibernate基本配置
NHibernate配置要注意的有:
1、NHibernate需要一个自定义的配置节点,一般放在Web.config里或App.config里面,当然你可以自己定义实际位置。
示例如下:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name ="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate"/> (1) </configSections> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > <session-factory name="Dao"> <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property> (2) <property name="connection.connection_string"> Data Source=KISSDODOG-PC;Initial Catalog=Test;uid=sa;pwd=123; (3) </property> <property name ="dialect">NHibernate.Dialect.MsSql2008Dialect</property> (4) <mapping assembly ="Model"/> (5) </session-factory> </hibernate-configuration> </configuration>
(1)、声明自定义配置节点
name:自定义配置节点名称。
type:处理程序位置。
(2)、声明是哪一个数据库驱动程序。
(3)、数据库连接。
(4)、所使用的SQL方言,通过这个方言,NHibernate才知道要将你写的查询语句,翻译成何种数据库的SQL语句。
(5)、设定映射文件默认所在的程序集。‘
NHibernate的配置节点并不止5个,想知道更详细的配置节点说明:http://www.cnblogs.com/kissdodog/archive/2013/02/21/2919873.html
另外,这一个配置节点文件,并不一定要放在Web.config或App.config里,例如你可以定义一个hibernate.cfg.xml文件,然后创建ISessionFactory时指定位置:
ISessionFactory sessionFactory = new Configuration().Configure(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "hibernate.cfg.xml").BuildSessionFactory();
这里要小心"new Configuration().Configure()",如果没有Configure("xxx.cfg.xml")就是从配置文件加载,有就是从自定义文件(如:xxx.cfg.xml)加载。
注意,此hibernate.cfg.xml文件名可以随意起,但是要设置为始终复制。否则将报告如下错误:
An exception occurred during configuration of persistence layer.
2、NHibernate的映射文件一定要设为嵌入的资源。
3、NHibernate的实体类所有的属性都要加上virtual-虚属性,具体将在持久化类的文章中说明,下面给个例子:
public class PersonModel { public virtual int Id { get; set; } public virtual string Name { get; set; } }
NHibernate作为一个ORM框架,它需要知道如何将数据库的表与对应的实体类相关联,NHibernate通过映射文件的方式来获得这方面的信息。
二、获取映射文件相关配置
NHibernate中的映射文件以hbm.xml为后缀结束,NHibernate获取映射文件的方法有3种方法。
1、从config程序配置文件获取映射文件位置
NHibernate运行在.Net程序上,需要自己提供一个自定义配置节点,这个配置节点里面包含了数据库连接,什么数据库等等信息。其中就包括了配置文件所在位置的信息。
NHibernate会直接从Web.config或App.config文件上的配置节点上读取这个节点,然后从节点指定的程序集去查找映射文件。
<mapping assembly ="Nx.Repository"/>
以上这个配置节点所保存的就是映射文件默认所在的程序集。这样当程序启动时,NHibernate就会自动去Nx.Repository寻找*.hbm.xml映射文件。
如果NHibernate找不到映射文件,则可能会报如下错误:
“/”应用程序中的服务器错误。
No persister for: xxx.xxx
2、编程的方式,写在代码里
(1)、AddFile 指定映射文件
ISessionFactory sessionFactory = new Configuration().Configure().AddFile(@"C:UsersAdministratorDesktopNHibernate学习ModelMappingPerson.hbm.xml").BuildSessionFactory();
注意,当你不写全路径的时候,也就是只写个文件名,那么NHibernate就会从配置文件读取程序集,到配置文件中指定的程序集去加载此映射文件。如果配置文件并不指定程序集,那么就从当前程序集中查找指定名的映射文件。但这种方式,不必设置嵌入的资源,但要记得设置为始终复制。
Configuration cfg = new Configuration().AddFile("Mapping/Person.hbm.xml"); ISessionFactory sessionFactory = cfg.BuildSessionFactory();
这种方法只是指定一个文件,但是可以链式指定多个如:AddFile("f1").AddFile("f2")。
(2)、AddAssembly
还有另外一种方法,在创建Configuration时指定程序集。
Configuration cfg = new Configuration().AddAssembly("Model"); //Model为映射文件所在程序集名称 ISessionFactory sessionFactory = cfg.BuildSessionFactory();
这种方法,即使.config配置文件里<mapping assembly=""/>节点为空也没关系,NHibernate会自动到指定的程序集里查找所有以.hbm.xml结尾的文件。
(3)、AddClass
这种方式,可以消除程序对文件路径字符串的硬编码。
Configuration cfg = new Configuration().AddClass(typeof(Model.Person)); ISessionFactory sessionFactory = cfg.BuildSessionFactory();
但是缺点也非常明显,类名必须与映射文件的名称相同。不然,编译就无法通过,因为Person类都找不到。另外,映射文件Person.hbm.xml必须放在根目录。
NHibernate会自动到程序中去查找名为Person.hbm.xml文件。
三、持久化类中成员标量的要求
作为被NHibernate使用的持久化类,必须满足以下几点要求:
1、声明读写属性
在NHibernate的使用中,持久化类的成员变量必须声明对应的属性,NHibernate支持public、internal、protected三种访问修饰符。
2、提供标识属性
持久化类必须提供一个标识属性,标识属性对应数据库的主键。
当然这个是可选的,并非强制性,但是强烈建议这么做。这个标识属性可以叫任何名字,任何类型。
3、属性必须是非密封的和虚的
持久化类中所有的属性,必须声明为非密封的,也就是不能带有sealed。而且必须带有virtual关键字。
继承持久化的类,如果想作为持久化类,也必须满足以上3点条件。
四、实现ILifecycle接口,实现回调(Callbacks)操作
持久化类可以实现一个叫ILifecycle的接口,从而实现一些回调方法,比如可以让持久化对象在save、load之后,delete、update之前进行一些初始化或清除的工作。
注意在实现接口的时候,方法也必须声明为virtual的和public/internal的。
我们先来看看接口的代码:
public interface ILifecycle { LifecycleVeto OnSave(ISession s); LifecycleVeto OnUpdate(ISession s); LifecycleVeto OnDelete(ISession s); void OnLoad(ISession s, object id); }
方法说明:
OnSave: 对象即将被save或insert时调用。
OnUpdate: 对象即将被update时调用。
OnDelete: 对象即将被delete时调用。
OnLoad: 对象被装载后,第一时间调用。
示例:
public class PersonModel : ILifecycle { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual LifecycleVeto OnDelete(NHibernate.ISession s) { throw new NotImplementedException(); } public virtual void OnLoad(NHibernate.ISession s, object id) { this.Name = "加载时修改姓名!"; Console.WriteLine("在加载时调用!"); //在这里可以初始化等操作 } public virtual LifecycleVeto OnSave(NHibernate.ISession s) { throw new NotImplementedException(); } public virtual LifecycleVeto OnUpdate(NHibernate.ISession s) { throw new NotImplementedException(); } }
调用代码:
static void Main(string[] args) { PersonDao dao = new PersonDao(); PersonModel p = dao.GetPersonById(3); Console.WriteLine(p.Id + " " + p.Name); Console.ReadKey(); }
输出结果如下:
如果OnSave(),OnUpdate或OnDelete返回了LifecycleVeto.veto,那么这些操作会被取消了。
五、持久化类实例的状态
一个持久化类实例,可能处于以下3种状态。这三种状态与ISession实例有关。
- 瞬态(transient)
- 持久化(persistent)
- 脱管(detached)
1、瞬态
该持久化实例未与任何ISession实例关联过,没有持久化标识。
Person p = new Person();
如上面这个p实例就是瞬态。
2、持久化
该持久化实例与ISession有关联,它拥有持久化标识。持久化标识与CLR标识(内存中的位置)等价。通常是指刚刚从数据库里读出来或是刚刚保存入数据库的对象实例。
ISession session = sessionFactory.OpenSession(); Person p = session.Get<Person>(Id);
如上面这个p,就是持久化状态。
3、脱管
实例曾经与ISession关联过,但是那个ISession关闭了。它拥有持久化标识,并且可能在数据库有与其对应的一条记录。如果此时,又与ISession关联上,它就转变为了持久化状态。
ISession session = sessionFactory.OpenSession(); Person p = session.Get<Person>(Id); session.Close();
在Close()之后,p对象就是脱管状态了。
4、瞬态-持久化转变
ISession session = sessionFactory.OpenSession(); Person p = new Person(10,"张三"); //瞬态 Console.WriteLine(session.Contains(p)); //输出 false session.Save(p); Console.WriteLine(session.Contains(p)); //输出true 现在p是持久化状态了
5、持久化状态-脱管转变
ISession session = sessionFactory.OpenSession(); PersonModel p = session.Get<PersonModel>(2); Console.WriteLine(session.Contains(p)); //输出 ture 持久化状态 session.Close(); Console.WriteLine(sessionFactory.OpenSession().Contains(p)); //输出 false 脱管
了解持久化状态,对理解NHibernate缓存,离线查询等功能是必要的。