2017-01-09 3 views
1

Я начинаю сессию в начале единицы работы и закрываю ее в конце. Единица работы выражается несколькими методами.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», а также не совпадает с таблицами. В одной таблице это «Поле1», а в другом - «Поле2». Поэтому я не могу использовать что-то вроде nhSession.Get(instance.Id). Мой метод Delete<T>(T instance) принимает экземпляр сущности для удаления в качестве параметра. Он не получает значение первичного ключа для удаления.

Для получения дополнительной информации, пожалуйста, обратитесь к моему вопросу other. Этот вопрос обсуждает проблему UPDATE и то, как я ее исправил; но сценарий схож.

Edit 1

Ответа на этот вопрос «@Ricardo Переса» не работает, как есть, но я его код немного изменен.

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. Любой способ получить идентификатор объекта, который НЕ связан с сеансом?

+0

Если это прокси-сервер: http://stackoverflow.com/a/10328489/1486443. – Najera

ответ

1

Вам нужно достать 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; 
} 
+0

Да, это так ... если вы добавите ссылку на пространство имен System.Linq. Это метод расширения. –

+0

Thanks; Да. Но он все еще не возвращает объект в кеш. Мое предположение: 'x.Key.Identifier == key' терпит неудачу. Я передаю экземпляр объекта как ключ, а код ожидает «Идентификатор». У меня нет значения идентификатора; У меня только экземпляр объекта. Это аналогичная проблема, о которой я упомянул в ** Edit 1 ** выше. Любой способ получить идентификатор объекта, который НЕ связан с сеансом? –

+0

Вам нужно отладить его, я всегда использовал этот подход (тот же метод GetInstanceFromCache, только другое имя). Чтобы получить идентификатор объекта, вы можете использовать это: var entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName (EntityType); \t \t \t AbstractEntityPersister persister = (sessionFactory as ISessionFactoryImplementor) .TryGetEntityPersister (entityName) как AbstractEntityPersister; \t \t \t если (стойкая бактерия! = NULL) \t \t \t { \t \t \t \t возвращение (entityType.GetProperty (persister.IdentifierPropertyName)); \t \t \t} –

1

С кодом разместил «@Ricardo Переса», я был в состоянии решить. Но точный код не работает. Мне нужно было немного изменить его следующим образом:

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; 
} 
Смежные вопросы