Подтвердить что ты не робот

Hibernate: как получить список всех объектов, находящихся в данный момент сеанса

Я получаю хороший, старый и страшный TransientObjectException, и, как часто бывает в таком случае, у меня возникают проблемы с поиском того, какая тонкая ошибка в коде вызывает проблему.

Мой вопрос: есть ли способ получить список каждого объекта, который находится в текущем сеансе Hibernate?

Вероятно, я разрешил текущую проблему к моменту получения ответа на этот вопрос, но, во всяком случае, возможность перечислить все, что является сеансом, поможет в следующий раз.

4b9b3361

Ответ 1

Hibernate не раскрывает свои внутренние функции для общественности, поэтому вы не найдете то, что ищете в публичном API. Однако вы можете найти свой ответ в классах реализации интерфейсов Hibernate: Этот метод (взятый из http://code.google.com/p/bo2/source/browse/trunk/Bo2ImplHibernate/main/gr/interamerican/bo2/impl/open/hibernate/HibernateBo2Utils.java) будет определять, существует ли объект в сеансе:

public static Object getFromSession
        (Serializable identifier, Class<?> clazz, Session s) {              
    String entityName = clazz.getName();
    if(identifier == null) {
       return null;
    }      
    SessionImplementor sessionImpl = (SessionImplementor) s;
    EntityPersister entityPersister = sessionImpl.getFactory().getEntityPersister(entityName);
    PersistenceContext persistenceContext = sessionImpl.getPersistenceContext();
    EntityKey entityKey = new EntityKey(identifier, entityPersister, EntityMode.POJO);
    Object entity = persistenceContext.getEntity(entityKey);
    return entity;
    }

Если вы развернете немного больше, вы увидите, что единственная реализация PersistenceContext - org.hibernate.engine.StatefulPersistenceContext. Этот класс имеет следующие коллекции:

// Loaded entity instances, by EntityKey
private Map entitiesByKey;

// Loaded entity instances, by EntityUniqueKey
private Map entitiesByUniqueKey;

// Identity map of EntityEntry instances, by the entity instance
private Map entityEntries;

// Entity proxies, by EntityKey
private Map proxiesByKey;

// Snapshots of current database state for entities
// that have *not* been loaded
private Map entitySnapshotsByKey;

// Identity map of array holder ArrayHolder instances, by the array instance
private Map arrayHolders;

// Identity map of CollectionEntry instances, by the collection wrapper
private Map collectionEntries;

// Collection wrappers, by the CollectionKey
private Map collectionsByKey; //key=CollectionKey, value=PersistentCollection

// Set of EntityKeys of deleted objects
private HashSet nullifiableEntityKeys;

// properties that we have tried to load, and not found in the database
private HashSet nullAssociations;

// A list of collection wrappers that were instantiating during result set
// processing, that we will need to initialize at the end of the query
private List nonlazyCollections;

// A container for collections we load up when the owning entity is not
// yet loaded ... for now, this is purely transient!
private Map unownedCollections;

// Parent entities cache by their child for cascading
// May be empty or not contains all relation 
private Map parentsByChild;

Итак, что вам нужно сделать, это передать PersistenceContext в StatefulPersistenceContext, а затем использовать рефлексию, чтобы получить нужную вам частную коллекцию, а затем повторить ее.

Я настоятельно рекомендую вам сделать это только при отладке кода. Это не общедоступный API, и он может быть заблокирован более новыми версиями Hibernate.

Ответ 2

Нашел сообщение @nakosspy очень полезно. Вдохновленный его сообщением, я добавил этот очень простой метод утилиты, который выводит содержимое сеанса Hibernate.

Как говорит nakosspy, это ТОЛЬКО для целей отладки, поскольку это HACK.

    public static void dumpHibernateSession(Session s) {
    try {
        SessionImplementor sessionImpl = (SessionImplementor) s;
        PersistenceContext persistenceContext = sessionImpl.getPersistenceContext();
        Field entityEntriesField = StatefulPersistenceContext.class.getDeclaredField("entityEntries");
        entityEntriesField.setAccessible(true);
        IdentityMap map = (IdentityMap) entityEntriesField.get(persistenceContext);
        log.info(map);
    } catch (Exception e)
    {
        log.error(e);
    }

}