NHibernate:如何从会话缓存中获取实体实例



我在工作单元开始时开始会话,在结束时结束会话。工作单元分布在多个方法中。

在一种方法中,我使用Get方法加载实体。所以它位于会话缓存中。实体实例是该方法的本地实例。所以当方法范围结束时,实体实例是不可访问的。但实体仍在会话缓存中。

现在,第二个方法创建实体的新实例并尝试删除它。这将按预期抛出NonUniqueObjectException

以下是我可以想象但无法实现的解决方案:

public void Delete<T>(T instance) where T : BaseEntity
{
try
{
nhSession.Delete(instance);
}
catch(NonUniqueObjectException)
{
T instanceFromCache = GetInstanceFromCache<T>(instance);
nhSession.Evict(instanceFromCache);
nhSession.Delete(instance);
}
}

如果我能以某种方式从会话缓存中获取实体实例,我就可以Evict它,希望问题能得到解决。但我无法实现我想象中的GetInstanceFromCache方法。

我尝试过使用nhSession.Get,但这对我的场景没有帮助。我的数据库中的主键列名是NOT";id";而且在不同的表中也不一样。在一张表中,它是";字段1";另一方面是";字段2";。所以我不能使用nhSession.Get(instance.Id)这样的东西。我的Delete<T>(T instance)方法接收实体实例作为参数删除。它不接收要删除的主键的值。

更多信息,请参阅我的另一个问题。这个问题讨论了UPDATE问题以及我是如何解决它的;但情况类似。

编辑1

由"@Ricardo Peres";不能正常工作,但我对他的代码做了一些修改。

public static TEntity GetInstanceFromCache<TEntity>(this ISession nhSession, object instance) where TEntity : BaseEntity
{
var sessionImpl = nhSession.GetSessionImplementation();
foreach(BaseEntity baseEntity in sessionImpl.PersistenceContext.EntityEntries.Keys)
{
if(baseEntity is TEntity)
{
TEntity instanceFromCache = (TEntity)baseEntity;
if(nhSession.GetIdentifier(instanceFromCache) == nhSession.GetIdentifier(instance))
return baseEntity as TEntity;
}
}
return null;
}

调用nhSession.GetIdentifier(instance)抛出一个预期的异常TransientObjectException("实例未与此会话关联")。这是因为instance对于nhSession是未知的。有什么方法可以获得和会话无关的实体的标识符?

您需要掌握PersistenceContext,如下所示:

using System.Linq;
using NHibernate;   
public static T GetInstanceFromCache<T>(this ISession session, object key) where T : class
{
var entity = session.GetSessionImplementation().PersistenceContext.EntitiesByKey.SingleOrDefault(x => x.Value is T && x.Key.Identifier == key);
return entity as T;
}

使用@RicardoPeres提供的代码,我能够解决它。但确切的代码对我不起作用。我对它进行了如下修改:

public static TEntity GetInstanceFromCache<TEntity>(this ISession nhSession, object instance) where TEntity : BaseEntity
{
object detachedIdentifier = GetDetachedEntityId<TEntity>(instance, nhSession.SessionFactory);
var sessionImpl = nhSession.GetSessionImplementation();
foreach(BaseEntity baseEntity in sessionImpl.PersistenceContext.EntityEntries.Keys)
{
if(baseEntity is TEntity)
{
TEntity instanceFromCache = (TEntity)baseEntity;
string idFromCache = Convert.ToString(nhSession.GetIdentifier(instanceFromCache));
string idNew = Convert.ToString(detachedIdentifier);
if(idFromCache == idNew)
return baseEntity as TEntity;
}
}
return null;
//Another way-----------------------------
//var entity = nhSession.GetSessionImplementation().PersistenceContext.EntitiesByKey.SingleOrDefault(x => x.Value is TEntity && Convert.ToString(x.Key.Identifier) == Convert.ToString(detachedIdentifier));
//return entity.Value as TEntity;
//Another way-----------------------------
}
public static object GetDetachedEntityId<TEntity>(object instance, ISessionFactory sessionFactory) where TEntity : BaseEntity
{
Type entityType‌​ = typeof(TEntity);
var entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType‌​);
AbstractEntityPersister persister = (sessionFactory as ISessionFactoryImplementor).TryGetEntityPersister(entityName‌​) as AbstractEntityPersister;
if(persister != null)
{
PropertyInfo idPropertyInfo = entityType.GetProperty(persister.IdentifierPropertyName);
object identifier = idPropertyInfo.GetValue(instance, null);
return identifier;
}
return null;
}

最新更新