Как использовать отложенную загрузку объектов в веб-приложении Java EE? - PullRequest
3 голосов
/ 08 июня 2011

В моем веб-приложении я загружаю много сущностей, чтобы отобразить их в виде таблицы. Я могу щелкнуть по каждой табличке, чтобы получить «подробную информацию» о конкретной организации.

Для меня было очевидным не загружать «подробную информацию» для просмотра таблицы, а только тогда, когда кто-то хочет ее увидеть (щелкает строку).

Просто установка (fetch = FetchType.LAZY) для этих полей не сработала, потому что объекты извлекаются после выборки, и в моем WebApp будут нулевые значения.

Хорошо, следующее, что я сделал, это предотвратил отсоединение, поместив мои операции извлечения в StatefulSessionBean с расширенным PersistenceContext.

@PersistenceContext(unitName="unitname", type=PersistenceContextType.EXTENDED) private EntityManager em;

Это работает, но также вызывает странные побочные эффекты (особенно ConcurrentAccessExceptions при некоторых перезагрузках страницы, которые я мог бы исправить, установив некоторые свойства openjpa) Сервлеты нуждаются в собственных загружающих ejbs, так как они не объединяются с SFSB. Кажется, в большинстве случаев все работает нормально, но я ожидаю, что s ** t скоро поразит вентилятор.

У меня вопрос, не ошибся ли я. Все это кажется мне немного неловким. Использование bean-компонента с состоянием, когда нет реального разговора и пользователь может уйти в любое время, не вызывая какой-либо метод @ Remove-Method. Необходимость закрыть ресурсы по тайм-ауту, когда пользователь давно ушел, что приводит к множеству открытых неиспользуемых SFSB.

LazyLoading - это довольно простая вещь, но в среде Java EE я не понимаю, как это сделать. Какова лучшая практика?

Спасибо.

UPDATE

теперь я вручную получаю поля

@SuppressWarnings("unchecked")
public <T extends BasicEntity> T loadLazyField(T entity, String field) throws NoSuchFieldException {
    if (!typeHasField(entity.getClass(), field)) {
        throw new NoSuchFieldException(entity.getClass().getSimpleName() + " has no field called " + field);
    }

    String queryString = String.format("SELECT x FROM %s x WHERE x = :entity LEFT JOIN FETCH x.%s", entity.getClass()
            .getSimpleName(), entity, field);
    Query q = em.createQuery(queryString);
    q.setParameter("entity", entity);
    return (T) q.getSingleResult();
}

@SuppressWarnings("unchecked")
public <T extends BasicEntity> T loadLazyFields(T entity, String[] fields) throws NoSuchFieldException {
    String queryString = String.format("SELECT x FROM %s x WHERE x = :entity", entity.getClass().getSimpleName());

    for (String field : fields) {
        if (!typeHasField(entity.getClass(), field)) {
            throw new NoSuchFieldException(entity.getClass().getSimpleName() + " has no field called " + field);
        }
        queryString += String.format(" LEFT JOIN FETCH x.%s", field);
    }
    Query q = em.createQuery(queryString);
    q.setParameter("entity", entity);
    return (T) q.getSingleResult();

}

private boolean typeHasField(Class<?> type, String field) {
    try {
        type.getDeclaredField(field);
        return true;
    } catch (NoSuchFieldException e) {
        return false;
    }
}

1 Ответ

1 голос
/ 08 июня 2011

Вам нужен шаблон дизайна под названием «Открыть сеанс в представлении», сохраняющий сеанс персистентности открытым на этапе рендеринга страницы. Эта функция предоставляется интегрированными структурами, такими как Seam.

Я не уверен, поддерживается ли это JSF2, так как многие функции из Seam2 перенесены в JavaEE6. В любом случае, вам стоит взглянуть на Seam (хотя с Seam3 сложно что-то запустить).

...