📄 defaultloadeventlistener.cs
字号:
else
{
ck = null;
}
object entity;
try
{
entity = Load(@event, persister, keyToLoad, options);
}
finally
{
if (persister.HasCache)
{
persister.Cache.Release(ck, sLock);
}
}
object proxy = @event.Session.PersistenceContext.ProxyFor(persister, keyToLoad, entity);
return proxy;
}
/// <summary>
/// Coordinates the efforts to load a given entity. First, an attempt is
/// made to load the entity from the session-level cache. If not found there,
/// an attempt is made to locate it in second-level cache. Lastly, an
/// attempt is made to load it directly from the datasource.
/// </summary>
/// <param name="event">The load event </param>
/// <param name="persister">The persister for the entity being requested for load </param>
/// <param name="keyToLoad">The EntityKey representing the entity to be loaded. </param>
/// <param name="options">The load options. </param>
/// <returns> The loaded entity, or null. </returns>
protected virtual object DoLoad(LoadEvent @event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
{
if (log.IsDebugEnabled)
{
log.Debug("attempting to resolve: " + MessageHelper.InfoString(persister, @event.EntityId, @event.Session.Factory));
}
object entity = LoadFromSessionCache(@event, keyToLoad, options);
if (entity == RemovedEntityMarker)
{
log.Debug("load request found matching entity in context, but it is scheduled for removal; returning null");
return null;
}
if (entity == InconsistentRTNClassMarker)
{
log.Debug("load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null");
return null;
}
if (entity != null)
{
if (log.IsDebugEnabled)
{
log.Debug("resolved object in session cache: " + MessageHelper.InfoString(persister, @event.EntityId, @event.Session.Factory));
}
return entity;
}
entity = LoadFromSecondLevelCache(@event, persister, options);
if (entity != null)
{
if (log.IsDebugEnabled)
{
log.Debug("resolved object in second-level cache: " + MessageHelper.InfoString(persister, @event.EntityId, @event.Session.Factory));
}
return entity;
}
if (log.IsDebugEnabled)
{
log.Debug("object not resolved in any cache: " + MessageHelper.InfoString(persister, @event.EntityId, @event.Session.Factory));
}
return LoadFromDatasource(@event, persister, keyToLoad, options);
}
/// <summary>
/// Performs the process of loading an entity from the configured underlying datasource.
/// </summary>
/// <param name="event">The load event </param>
/// <param name="persister">The persister for the entity being requested for load </param>
/// <param name="keyToLoad">The EntityKey representing the entity to be loaded. </param>
/// <param name="options">The load options. </param>
/// <returns> The object loaded from the datasource, or null if not found. </returns>
protected virtual object LoadFromDatasource(LoadEvent @event, IEntityPersister persister, EntityKey keyToLoad, LoadType options)
{
ISessionImplementor source = @event.Session;
object entity = persister.Load(@event.EntityId, @event.InstanceToLoad, @event.LockMode, source);
if (@event.IsAssociationFetch && source.Factory.Statistics.IsStatisticsEnabled)
{
source.Factory.StatisticsImplementor.FetchEntity(@event.EntityClassName);
}
return entity;
}
/// <summary>
/// Attempts to locate the entity in the session-level cache.
/// </summary>
/// <param name="event">The load event </param>
/// <param name="keyToLoad">The EntityKey representing the entity to be loaded. </param>
/// <param name="options">The load options. </param>
/// <returns> The entity from the session-level cache, or null. </returns>
/// <remarks>
/// If allowed to return nulls, then if the entity happens to be found in
/// the session cache, we check the entity type for proper handling
/// of entity hierarchies.
/// If checkDeleted was set to true, then if the entity is found in the
/// session-level cache, it's current status within the session cache
/// is checked to see if it has previously been scheduled for deletion.
/// </remarks>
protected virtual object LoadFromSessionCache(LoadEvent @event, EntityKey keyToLoad, LoadType options)
{
ISessionImplementor session = @event.Session;
object old = session.GetEntityUsingInterceptor(keyToLoad);
if (old != null)
{
// this object was already loaded
EntityEntry oldEntry = session.PersistenceContext.GetEntry(old);
if (options.IsCheckDeleted)
{
Status status = oldEntry.Status;
if (status == Status.Deleted || status == Status.Gone)
{
return RemovedEntityMarker;
}
}
if (options.IsAllowNulls)
{
IEntityPersister persister = @event.Session.Factory.GetEntityPersister(@event.EntityClassName);
if (!persister.IsInstance(old, @event.Session.EntityMode))
{
return InconsistentRTNClassMarker;
}
}
UpgradeLock(old, oldEntry, @event.LockMode, session);
}
return old;
}
/// <summary> Attempts to load the entity from the second-level cache. </summary>
/// <param name="event">The load event </param>
/// <param name="persister">The persister for the entity being requested for load </param>
/// <param name="options">The load options. </param>
/// <returns> The entity from the second-level cache, or null. </returns>
protected virtual object LoadFromSecondLevelCache(LoadEvent @event, IEntityPersister persister, LoadType options)
{
ISessionImplementor source = @event.Session;
bool useCache = persister.HasCache && ((source.CacheMode & CacheMode.Get) == CacheMode.Get)
&& @event.LockMode.LessThan(LockMode.Read);
if (useCache)
{
ISessionFactoryImplementor factory = source.Factory;
CacheKey ck = new CacheKey(@event.EntityId, persister.IdentifierType, persister.RootEntityName, source.EntityMode, factory);
object ce = persister.Cache.Get(ck, source.Timestamp);
if (factory.Statistics.IsStatisticsEnabled)
{
if (ce == null)
factory.StatisticsImplementor.SecondLevelCacheMiss(persister.Cache.RegionName);
else
factory.StatisticsImplementor.SecondLevelCacheHit(persister.Cache.RegionName);
}
if (ce != null)
{
CacheEntry entry = (CacheEntry)persister.CacheEntryStructure.Destructure(ce, factory);
// Entity was found in second-level cache...
// NH: Different behavior (take a look to options.ExactPersister (NH-295))
if (!options.ExactPersister || persister.EntityMetamodel.SubclassEntityNames.Contains(entry.Subclass))
{
return AssembleCacheEntry(entry, @event.EntityId, persister, @event);
}
}
}
return null;
}
private object AssembleCacheEntry(CacheEntry entry, object id, IEntityPersister persister, LoadEvent @event)
{
object optionalObject = @event.InstanceToLoad;
IEventSource session = @event.Session;
ISessionFactoryImplementor factory = session.Factory;
if (log.IsDebugEnabled)
{
log.Debug("assembling entity from second-level cache: " + MessageHelper.InfoString(persister, id, factory));
}
IEntityPersister subclassPersister = factory.GetEntityPersister(entry.Subclass);
object result = optionalObject ?? session.Instantiate(subclassPersister, id);
// make it circular-reference safe
TwoPhaseLoad.AddUninitializedCachedEntity(new EntityKey(id, subclassPersister, session.EntityMode), result, subclassPersister, LockMode.None, entry.AreLazyPropertiesUnfetched, entry.Version, session);
IType[] types = subclassPersister.PropertyTypes;
object[] values = entry.Assemble(result, id, subclassPersister, session.Interceptor, session); // intializes result by side-effect
TypeFactory.DeepCopy(values, types, subclassPersister.PropertyUpdateability, values, session);
object version = Versioning.GetVersion(values, subclassPersister);
if (log.IsDebugEnabled)
{
log.Debug("Cached Version: " + version);
}
IPersistenceContext persistenceContext = session.PersistenceContext;
persistenceContext.AddEntry(result, Status.Loaded, values, id, version, LockMode.None, true, subclassPersister, false, entry.AreLazyPropertiesUnfetched);
// TODO H3.2 subclassPersister.AfterInitialize(result, entry.AreLazyPropertiesUnfetched, session);
persistenceContext.InitializeNonLazyCollections();
// upgrade the lock if necessary:
//lock(result, lockMode);
//PostLoad is needed for EJB3
//TODO: reuse the PostLoadEvent...
PostLoadEvent postLoadEvent = new PostLoadEvent(session);
postLoadEvent.Entity = result;
postLoadEvent.Id = id;
postLoadEvent.Persister = persister;
IPostLoadEventListener[] listeners = session.Listeners.PostLoadEventListeners;
for (int i = 0; i < listeners.Length; i++)
{
listeners[i].OnPostLoad(postLoadEvent);
}
return result;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -