2017-01-09 2 views
1

작업 단위의 시작 부분에서 세션을 시작하고 세션의 끝에서 닫습니다. 작업 단위는 여러 가지 방법으로 작성됩니다.NHibernate : 세션 캐시에서 엔티티 인스턴스를 얻는 방법?

한 가지 방법으로 Get 메서드를 사용하여 엔티티를로드합니다. 그래서 이것은 세션 캐시에 있습니다. Entity 인스턴스는 메서드에 대해 로컬입니다. 따라서 메소드 범위가 끝나면 엔티티 인스턴스에 액세스 할 수 없습니다. 그러나 엔터티는 여전히 세션 캐시에 있습니다.

이제 두 번째 방법은 엔티티의 새 인스턴스를 만들고 삭제하려고 시도합니다. 예상대로 NonUniqueObjectException이 throw됩니다.

에 따라 내가 상상할 수있는 솔루션이지만, 구현할 수 없습니다 : 어떻게 든 세션 캐시에서 개체 인스턴스를 얻을 수 있다면, 나는 그것을 Evict 수 잘하면 문제가 해결됩니다

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); 
    } 
} 

. 그러나 나는 가상의 GetInstanceFromCache 메서드를 구현할 수 없습니다.

nhSession.Get을 사용해 보았지만, 내 시나리오에서는 도움이되지 않습니다. 내 데이터베이스의 기본 키 열 이름은 "id"가 아니며 테이블간에 동일하지 않습니다. 한 테이블에서 "Field1"이고 다른 테이블에서는 "Field2"입니다. 그래서 nhSession.Get(instance.Id)과 같은 것을 사용할 수 없습니다. 내 Delete<T>(T instance) 메서드는 매개 변수로 삭제할 엔터티 인스턴스를받습니다. 삭제할 기본 키의 값을받지 못합니다.

자세한 내용은 other 질문을 참조하십시오. 이 질문은 UPDATE 문제와 그 문제점에 대해 논의합니다. 그러나 시나리오는 유사합니다. "@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 ("인스턴스가이 세션에 관련되지 않은") 발생. nhSessioninstance을 알 수 없기 때문입니다. 세션과 관련이없는 엔티티의 식별자를 가져 오는 방법은 무엇입니까?

+0

프록시가있는 경우 : http://stackoverflow.com/a/10328489/1486443. – Najera

답변

1

는이처럼 PersistenceContext 잡아해야합니다

"@Ricardo 페레스"에 의해 게시 된 코드와
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

감사합니다. 그렇습니다. 그러나 여전히 엔티티를 캐시에 반환하지 않습니다. 내 추측 :'x.Key.Identifier == key'는 실패합니다. 엔티티 인스턴스를 키로 전달하고 코드는 '식별자'를 기대합니다. 나는 식별자 값을 가지고 있지 않다. 엔티티 인스턴스 만 있습니다. 이것은 ** 편집 1 **에서 언급 한 비슷한 문제입니다. 세션과 관련이없는 엔티티의 식별자를 가져 오는 방법은 무엇입니까? –

+0

당신은 그것을 디버깅 할 필요가있다. 나는 항상이 접근법 (GetInstanceFromCache와 같은 메소드, 다른 이름 만 사용한다)을 사용한다. 엔티티의 ID를 얻으려면 다음을 사용할 수 있습니다. var entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName (entityType); \t \t \t AbstractEntityPersister로 persister = (sessionFactory as SessionFactoryImplementor) .TryGetEntityPersister (entityName); \t \t \t 경우 (persister = NULL!) \t \t \t \t { \t \t \t 창 (entityType.GetProperty (persister.IdentifierPropertyName)); \t \t \t} –

1

, 내가 그것을 해결할 수 있었다. 하지만 정확한 코드가 나를 작동하지 않습니다. 다음과 같이 조금 수정해야했습니다.

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; 
}