Отсоединить объект от контекста сохранения JPA / EJB3

Каким будет самый простой способ отсоединить конкретный объектный компонент JPA, который был получен через EntityManager. В качестве альтернативы, могу ли я сделать так, чтобы запрос возвращал отдельные объекты, чтобы они по существу действовали как «только для чтения»?

Причина, по которой я хочу это сделать, заключается в том, что я хочу изменить данные внутри bean-компонента - только в моем приложении, но никогда не сохраняю их в базе данных. В моей программе мне в конечном итоге приходится вызывать flush () для EntityManager, который сохранял бы все изменения из присоединенных сущностей в базе данных underyling, но я хочу исключить определенные объекты.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
56
0
74 103
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Насколько мне известно, единственные прямые способы сделать это:

  1. Зафиксировать txn - вероятно, не разумный вариант
  2. Очистить контекст сохранения - EntityManager.clear () - это жестоко, но очистит его
  3. Скопируйте объект - в большинстве случаев ваши объекты JPA сериализуемы, поэтому это должно быть легко (если не особенно эффективно).

Как фиксация txn вызывает отсоединение объекта?

Peter Davis 19.05.2011 21:59

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

Это может быть реализовано как конструктор копирования, например:

public Thing(Thing oldBean) {
  this.setPropertyOne(oldBean.getPropertyOne());
  // and so on
}

Потом:

Thing newBean = new Thing(oldBean);
Ответ принят как подходящий

К сожалению, в текущей реализации JPA, AFAIR, нет способа отключить один объект от диспетчера сущностей.

EntityManager.clear () отключит все объекты JPA, поэтому это может быть не подходящим решением во всех случаях, если у вас есть другие объекты, которые вы планируете поддерживать.

Поэтому лучше всего клонировать объекты и передавать клоны в код, который изменяет объекты. Поскольку о примитивных и неизменяемых полях объектов должным образом позаботится механизм клонирования по умолчанию, вам не придется писать много связующего кода (кроме глубокого клонирования любых агрегированных структур, которые у вас могут быть).

Это больше не так, теперь EM предоставляет метод отсоединения (сущности), начиная с JPA v2, см. Javax.persistence.EntityManager # detach

Frederik 08.08.2020 15:09

(может быть поздно отвечать, но может быть полезно другим)

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

Проще говоря. Используйте Hibernate или дождитесь JPA 2.0.

В Hibernate вы можете использовать session.evict (object) для удаления одного объекта из сеанса. В JPA 2.0, в черновике прямо сейчас, есть метод EntityManager.detach (object) для отделения одного объекта от контекста постоянства.

Сейчас ровно год спустя. У меня возникла эта проблема, и я не могу найти вызов метода «отсоединения» в EntityManager. По какой-то причине его уронили?

HDave 21.05.2010 09:47

Здесь download.oracle.com/javaee/6/api/javax/persistence/…

Lee Chee Kiam 13.04.2011 12:29

это быстро и грязно, но вы также можете сериализовать и десериализовать объект.

Предупреждаем, это может вызвать проблемы с отложенной загрузкой и отношениями JPA.

James McMahon 12.01.2010 16:33

Я думаю, вы также можете использовать метод EntityManager.refresh (Object o), если первичный ключ объекта не был изменен. Этот метод восстановит исходное состояние объекта.

Если вам нужно отсоединить объект от EntityManager и вы используете Hibernate в качестве базового уровня ORM, вы можете получить доступ к объекту Сессия гибернации и использовать метод Session.evict (Объект), упомянутый выше Маурисио Канадой.

public void detach(Object entity) {
    org.hibernate.Session session = (Session) entityManager.getDelegate();
    session.evict(entity);
}

Конечно, это сломается, если вы переключитесь на другого поставщика ORM, но я думаю, что это лучше, чем попытаться сделать глубокую копию.

Поскольку я использую SEAM и JPA 1.0, и моя система имеет функциональность, которая должна регистрировать все изменения полей, я создал объект значения или объект передачи данных, если те же поля объекта, которые необходимо регистрировать. Конструктор нового pojo:

    public DocumentoAntigoDTO(Documento documentoAtual) {
    Method[] metodosDocumento = Documento.class.getMethods();
    for(Method metodo:metodosDocumento){
        if (metodo.getName().contains("get")){
            try {
                Object resultadoInvoke = metodo.invoke(documentoAtual,null);
                Method[] metodosDocumentoAntigo = DocumentoAntigoDTO.class.getMethods();
                for(Method metodoAntigo : metodosDocumentoAntigo){
                    String metodSetName = "set" + metodo.getName().substring(3);
                    if (metodoAntigo.getName().equals(metodSetName)){
                        metodoAntigo.invoke(this, resultadoInvoke);
                    }
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

Если вы используете EclipseLink, у вас также есть варианты,

Используйте подсказку запроса, eclipselink.maintain-cache" = "false - все возвращенные объекты будут отсоединены.

Используйте EclipseLinkJpaEntityManagercopy() API, чтобы скопировать объект на желаемую глубину.

Если вы попали сюда, потому что действительно хотите передать объект через удаленную границу, вы просто вставляете код, чтобы обмануть спящего.

for(RssItem i : result.getChannel().getItem()){
}

Cloneable не будет работать, потому что он фактически копирует PersistantBag.

И забудьте об использовании сериализуемых потоков, потоков с байтовыми массивами и конвейерных потоков. создание потоков во избежание взаимоблокировок убивает всю концепцию.

Независимо от того, какую реализацию JPA вы используете, просто используйте entityManager.detach(object), он теперь в JPA 2.0 и является частью JEE6.

В JPA 1.0 (проверено с использованием EclipseLink) вы можете получить объект вне транзакции. Например, с транзакциями, управляемыми контейнером, вы можете:

public MyEntity myMethod(long id) {
    final MyEntity myEntity = retrieve(id);
    // myEntity is detached here
}

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public MyEntity retrieve(long id) {
    return entityManager.find(MyEntity.class, id);
}

В аналогичном случае я создал объект DTO, который расширяет постоянный объект сущности следующим образом:

class MyEntity
{
   public static class MyEntityDO extends MyEntity {}

}

Наконец, скалярный запрос получит желаемые неуправляемые атрибуты:

(Hibernate) select p.id, p.name from MyEntity P
(JPA)       select new MyEntity(p.id, p.name) from myEntity P

Я думаю, что есть способ выселить один объект из EntityManager, вызвав это

EntityManagerFactory emf;
emf.getCache().evict(Entity);

Это удалит конкретную сущность из кеша.

Это только вытесняет объект из кеша второго уровня, но не из кеша сеанса.

Lukasz Frankowski 25.04.2019 08:42

Другие вопросы по теме