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

时间:2017-01-09 12:31:30

标签: 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,但这在我的方案中没有帮助。我的数据库中的主键列名称不是“id”,并且它在表之间也不相同。在一个表中,它是“Field1”,在另一个表中是“Field2”。所以我不能使用像nhSession.Get(instance.Id)这样的东西。我的Delete<T>(T instance)方法接收要删除的实体实例作为参数。它不会收到要删除的主键值。

有关详细信息,请参阅我的other问题。该问题讨论了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。获取与会话无关的实体标识符的任何方法吗?

2 个答案:

答案 0 :(得分:2)

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

{{1}}

答案 1 :(得分:1)

使用“@Ricardo Peres”发布的代码,我能够解决它。但确切的代码不适用于我。我需要修改它,如下所示:

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;
}
相关问题