IT Share you

JPA / EJB3 지속성 컨텍스트에서 엔티티 분리

shareyou 2021. 1. 10. 19:20
반응형

JPA / EJB3 지속성 컨텍스트에서 엔티티 분리


EntityManager를 통해 얻은 특정 JPA Entity Bean을 분리하는 가장 쉬운 방법은 무엇입니까? 또는 쿼리가 분리 된 개체를 처음에 반환하여 본질적으로 '읽기 전용'으로 작동하도록 할 수 있습니까?

이 작업을 수행하려는 이유는 Bean 내의 데이터를 내 응용 프로그램에서만 수정하고 데이터베이스에 유지하지 않기 때문입니다. 내 프로그램에서 결국 EntityManager에서 flush ()를 호출해야하는데, 이는 연결된 엔터티에서 기본 데이터베이스로 모든 변경 사항을 유지하지만 특정 개체를 제외하고 싶습니다.


안타깝게도 현재 JPA 구현 인 AFAIR에서는 엔티티 관리자에서 하나의 객체를 연결 해제 할 수있는 방법이 없습니다.

EntityManager.clear ()는 모든 JPA 개체의 연결을 끊기 때문에 연결을 유지하려는 다른 개체가있는 경우 모든 경우에 적절한 솔루션이 아닐 수 있습니다.

따라서 가장 좋은 방법은 개체를 복제하고 개체를 변경하는 코드에 복제본을 전달하는 것입니다. 원시 및 불변 개체 필드는 기본 복제 메커니즘에 의해 적절한 방식으로 처리되므로 많은 연결 코드를 작성할 필요가 없습니다 (사용자가 보유하고있을 수있는 모든 집계 구조를 딥 복제하는 것 제외).


(답변하기에는 너무 늦을 수 있지만 다른 사람에게 유용 할 수 있음)

지금 JPA로 첫 번째 시스템을 개발 중입니다. 불행히도이 시스템이 거의 완성되었을 때이 문제에 직면했습니다.

간단히 말해서. Hibernate를 사용하거나 JPA 2.0을 기다리십시오.

Hibernate에서는 'session.evict (object)'를 사용하여 세션에서 하나의 객체를 제거 할 수 있습니다. 에서는 JPA 2.0 현재 드래프트에서 , 영속 컨텍스트에서 하나의 오브젝트를 분리하는 'EntityManager.detach (개체) "방법이있다.


어떤 JPA 구현을 사용하든 entityManager.detach(object)이제 JPA 2.0과 JEE6의 일부에 있습니다.


EntityManager에서 개체를 분리해야하고 기본 ORM 계층으로 Hibernate를 사용하는 경우 Hibernate Session 개체에 액세스 하고 Mauricio Kanada가 위에서 언급 한 Session.evict (Object) 메서드를 사용할 수 있습니다 .

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

물론 이것은 다른 ORM 제공 업체로 전환하면 깨질 수 있지만, 딥 카피를 만드는 것이 바람직하다고 생각합니다.


내가 아는 한,이를 수행하는 유일한 직접적인 방법은 다음과 같습니다.

  1. txn 커밋-아마도 합리적인 옵션이 아닐 것입니다.
  2. 지속성 컨텍스트 지우기-EntityManager.clear ()-잔인하지만 지울 수 있습니다.
  3. 객체 복사-대부분의 경우 JPA 객체는 직렬화 가능하므로 이는 매우 간단합니다 (특히 효율적이지 않은 경우).

사용 EclipseLink하는 경우 옵션도 있습니다.

쿼리 힌트를 사용하십시오 eclipselink.maintain-cache"="false.-반환 된 모든 개체가 분리됩니다.

EclipseLink JpaEntityManager copy()API를 사용하여 객체를 원하는 깊이로 복사합니다.


Bean에 속성이 너무 많지 않은 경우 새 인스턴스를 만들고 지속 된 Bean에서 모든 속성을 수동으로 설정할 수 있습니다.

이것은 복사 생성자로 구현 될 수 있습니다. 예를 들면 다음과 같습니다.

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

그때:

Thing newBean = new Thing(oldBean);

이것은 빠르고 더럽지 만 객체를 직렬화 및 역 직렬화 할 수도 있습니다.


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

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

실제로 원격 경계를 넘어서 엔티티를 전달하기를 원하기 때문에 여기에 온 경우 하이버 나치를 속이기 위해 코드를 입력하면됩니다.

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

Cloneable은 실제로 PersistantBag를 복사하기 때문에 작동하지 않습니다.

And forget about using serializable and bytearray streams and piped streams. creating threads to avoid deadlocks kills the entire concept.


I think there is a way to evict a single entity from EntityManager by calling this

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

This will remove particular entity from cache.


I think you can also use method EntityManager.refresh(Object o) if primary key of the entity has not been changed. This method will restore original state of the entity.

ReferenceURL : https://stackoverflow.com/questions/31446/detach-an-entity-from-jpa-ejb3-persistence-context

반응형