适用版本: NHibernate 2.1.2-GA
hibernate.cfg.xml配置为:
(原文链接 http://ddbiz.com/?p=150)
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
NHibernate 的一级缓存(first level cache)是session级别的,随着session的close被清除掉。
session.Get和session.Load都是加载一个对象,但是他们有一定的区别:
session.Get<T>(id) 有几个特性:
1. 从数据库中加载对象,如果对象不存在,则返回null;
2. 被正确加载的对象,对象本身所有的属性都会连同对象被缓存在内存中;
3. 如果在同一个session中指定id的对象已经被加载过(即存在于一级缓存中),那么此对象将被从缓存中加载,而不再访问数据库
如下面的此时代码:
#1 Guid uid = new Guid("b36db9fd-34d6-441a-bf17-931f22658183");
#2 ISession s = SessionManager.Instance.GetSession();
#3 log.InfoFormat("Try Load User:{0}", uid);
#4 TUser u = s.Get<TUser>(uid);
#5 if (u == null) log.InfoFormat("User {0} not found", uid);
#6 else log.InfoFormat("User {0} loaded", uid);
#7
#8 log.InfoFormat("Try reload User: {0}", uid);
#9 TUser u2 = s.Get<TUser>(uid);
#10 if (u == null) log.InfoFormat("User {0} not found", uid);
#11 else log.InfoFormat("User {0} reloaded", uid);
#1 2010-07-20 15:34:46,343 INFO mdi.opt.test - Try Get User:b36db9fd-34d6-441a-bf17-931f22658183
#2 2010-07-20 15:34:46,390 DEBUG NHibernate.SQL - SELECT tuser0_.Id as Id95_0_, tuser0_.Version as Version95_0_, tuser0_.UserType as UserType95_0_, tuser0_.Account as Account95_0_, ... FROM tuser tuser0_ WHERE tuser0_.Id=?p0;?p0 = b36db9fd-34d6-441a-bf17-931f22658183
#3 2010-07-20 15:34:46,468 INFO mdi.opt.test - User b36db9fd-34d6-441a-bf17-931f22658183, Account=suvizhang loaded
#4 2010-07-20 15:34:46,468 INFO mdi.opt.test - Try reGet User: b36db9fd-34d6-441a-bf17-931f22658183
#5 2010-07-20 15:34:46,468 INFO mdi.opt.test - User b36db9fd-34d6-441a-bf17-931f22658183, Account=suvizhang reloaded
两次加载,只有一个sql语句从数据库中装载数据: #2; 第二次加载数据则直接返回了内存数据。
如果要加载的 Guid("b36db9fd-34d6-441a-bf17-931f22658183") 不存在与数据库中,那么Get<TUser>(uid)将返回null。
session.Load<T>(uid) 的特性
如果 <T>的 default lazy 为 true,
1. session.Load<T>(uid) 返回一个 <T>Proxy对象
否则
2. 如果数据库中不存在此数据,则发生错误。
3. session.Load<T>(uid)同样要检测一级缓存,如果已经存在于缓存中,则直接返回数据。
其中2.和网络上讲的都不大一样,如果uid不存在与数据库,则同样返回的是一个 <T>proxy对象,只有在访问返回对象的具体属性时,才会发生错误,而不是在Load<T>的时候就发生错误。
如:
#1 Guid uid = new Guid("b36db9fd-34d6-441a-bf17-931f22658185");
#2 ISession s = SessionManager.Instance.GetSession();
#3 log.InfoFormat("Try Load User:{0}", uid);
#4 TUser u = s.Load<TUser>(uid);
#5 log.InfoFormat("User {0} loaded as {1}", uid, u.GetType().FullName);
#6 log.InfoFormat("User {0}, Account={1} loaded", uid, u.Account);
#7
#8 log.InfoFormat("Try reload User: {0}", uid);
#9 TUser u2 = s.Load<TUser>(uid);
#10 log.InfoFormat("User {0} loaded as {1}", uid, u.GetType().FullName);
#11 log.InfoFormat("User {0}, Account={1} loaded", uid, u.Account);
此例中, #1 代表的Guid在数据库中并不存在, #4返回的是一个 TUserproxy对象,此时并不发生错误;因为返回了一个代理对象,而该对象并不存在,所以#6中调用u.Account 是肯定会报错了。上例中的加载流程,可以从日志中发现:
#1 2010-07-20 16:47:06,421 INFO mdi.opt.test - Try Load User:b36db9fd-34d6-441a-bf17-931f22658183
#2 2010-07-20 16:47:22,109 DEBUG NHibernate.Event.Default.DefaultLoadEventListener - loading entity: [mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]
#3 2010-07-20 16:47:22,109 DEBUG NHibernate.Event.Default.DefaultLoadEventListener - creating new proxy for entity
#4 2010-07-20 16:47:22,156 DEBUG NHibernate.AdoNet.ConnectionManager - after autocommit
#5 ......
#6 2010-07-20 16:47:22,296 INFO NHibernate.Loader.Loader - SELECT tuser0_.Id as Id95_0_, tuser0_.Version as Version95_0_, tuser0_.UserType as UserType95_0_, tuser0_.Account as Account95_0_... FROM tuser tuser0_ WHERE tuser0_.Id=?p0
#7 2010-07-20 16:47:22,296 DEBUG NHibernate.SQL - SELECT tuser0_.Id as Id95_0_, tuser0_.Version as Version95_0_, tuser0_.UserType as UserType95_0_, tuser0_.Account as Account95_0_,... FROM tuser tuser0_ WHERE tuser0_.Id=?p0;?p0 = b36db9fd-34d6-441a-bf17-931f22658183
#8 2010-07-20 16:47:22,296 DEBUG NHibernate.Connection.DriverConnectionProvider - Obtaining IDbConnection from Driver
#9 2010-07-20 16:47:22,312 DEBUG NHibernate.AdoNet.AbstractBatcher - ExecuteReader took 4 ms
#10 2010-07-20 16:47:22,312 DEBUG NHibernate.AdoNet.AbstractBatcher - Opened IDataReader, open IDataReaders: 1
#11 2010-07-20 16:47:22,312 DEBUG NHibernate.Loader.Loader - processing result set
#12 2010-07-20 16:47:22,312 DEBUG NHibernate.Loader.Loader - result set row: 0
#13 2010-07-20 16:47:22,312 DEBUG NHibernate.Loader.Loader - result row: EntityKey[mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]
#14 2010-07-20 16:47:22,312 DEBUG NHibernate.Loader.Loader - Initializing object from DataReader: [mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]
#15 2010-07-20 16:47:22,328 DEBUG NHibernate.Persister.Entity.AbstractEntityPersister - Hydrating entity: [mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]
#16 2010-07-20 16:47:22,328 DEBUG NHibernate.Type.Int32Type - returning '1' as column: Version95_0_
#17 2010-07-20 16:47:22,328 DEBUG NHibernate.Type.PersistentEnumType - returning '0' as column: UserType95_0_
#18 2010-07-20 16:47:22,328 DEBUG NHibernate.Type.StringType - returning 'suvizhang' as column: Account95_0_
#19 ......
#20 2010-07-20 16:47:22,328 DEBUG NHibernate.Engine.TwoPhaseLoad - Version: 1
#21 2010-07-20 16:47:22,328 DEBUG NHibernate.Loader.Loader - done processing result set (1 rows)
#22 ......
#23 2010-07-20 16:47:22,359 DEBUG NHibernate.Loader.Loader - done entity load
#24 2010-07-20 16:47:44,531 INFO mdi.opt.test - User b36db9fd-34d6-441a-bf17-931f22658183 loaded as TUserProxy
#25 2010-07-20 16:47:45,500 INFO mdi.opt.test - User b36db9fd-34d6-441a-bf17-931f22658183, Account=suvizhang loaded
Load<T>(uid) 首先检查session的一级缓存,如果有此数据,则直接返回;如果缓存中没有此数据,则从数据库中加载数据,无论是否加载成功,都将返回一个TUserProxy(#24)对象;
#1 Guid uid = new Guid("b36db9fd-34d6-441a-bf17-931f22658183");
#2 ISession s = SessionManager.Instance.GetSession();
#3 log.InfoFormat("Try Load User:{0}", uid);
#4 TUser u = s.Get<TUser>(uid);
#5 log.InfoFormat("User {0} loaded as {1}", uid, u.GetType().FullName);
#6 log.InfoFormat("User {0}, Account={1} loaded", uid, u.Account);
#7
#8 log.InfoFormat("Try reload User: {0}", uid);
#9 TUser u2 = s.Load<TUser>(uid);
#10 log.InfoFormat("User {0} loaded as {1}", uid, u.GetType().FullName);
#11 log.InfoFormat("User {0}, Account={1} loaded", uid, u.Account);
#9 对已经在 #4装载过的数据,进行再次装载,log信息如下:
#1 2010-07-20 16:18:50,546 DEBUG NHibernate.Event.Default.DefaultLoadEventListener - loading entity: [mdi.opt.core.domain.member.TUser#b36db9fd-34d6-441a-bf17-931f22658183]
#2 2010-07-20 16:18:50,546 DEBUG NHibernate.Event.Default.DefaultLoadEventListener - entity found in session cache
(原文链接 http://ddbiz.com/?p=150)
参考文章:
更详细的关于代理的介绍 http://www.cnblogs.com/RicCC/archive/2010/03/18/nhibernate-lazy-load.html