Отсоединить сущность от контекста персистентности JPA / EJB3 - PullRequest
54 голосов
/ 28 августа 2008

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

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

Ответы [ 14 ]

56 голосов
/ 22 мая 2009

(может быть слишком поздно, чтобы ответить, но может быть полезно для других)

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

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

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

26 голосов
/ 27 августа 2012

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

19 голосов
/ 12 января 2010

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

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

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

18 голосов
/ 28 августа 2008

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

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

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

3 голосов
/ 31 марта 2011

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

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

Используйте API EclipseLink JpaEntityManager copy() для копирования объекта на нужную глубину.

3 голосов
/ 28 августа 2008

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

  1. Передать txn - вероятно, не разумный вариант
  2. Очистить контекст постоянства - EntityManager.clear () - Это жестоко, но очистило бы его
  3. Копирование объекта. Большую часть времени ваши JPA-объекты сериализуются, поэтому это должно быть легко (если не особенно эффективно).
1 голос
/ 03 сентября 2014

Имею дело с подобным случаем. Я создал объект 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
1 голос
/ 05 июня 2013

В 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);
}
1 голос
/ 31 марта 2011

Поскольку я использую 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();
            }
        }
    }
}
1 голос
/ 22 октября 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...