Pergunta

Qual seria a maneira mais fácil de desanexar um Entity Bean específico do JPA que foi adquirido através de um EntityManager.Como alternativa, eu poderia fazer com que uma consulta retornasse objetos desanexados em primeiro lugar, para que eles agissem essencialmente como 'somente leitura'?

A razão pela qual quero fazer isso é porque quero modificar os dados dentro do bean - apenas em meu aplicativo, mas nunca mantê-los no banco de dados.No meu programa, eventualmente terei que chamar flush() no EntityManager, o que persistiria todas as alterações das entidades anexadas ao banco de dados subjacente, mas quero excluir objetos específicos.

Foi útil?

Solução

Infelizmente, não há como desconectar um objeto do gerenciador de entidades na implementação atual do JPA, AFAIR.

EntityManager.clear() irá desconectar todos os objetos JPA, então essa pode não ser uma solução apropriada em todos os casos, se você tiver outros objetos que planeja manter conectados.

Portanto, sua melhor aposta seria clonar os objetos e passá-los para o código que altera os objetos.Como os campos de objetos primitivos e imutáveis ​​são tratados pelo mecanismo de clonagem padrão de maneira adequada, você não precisará escrever muito código de encanamento (além da clonagem profunda de quaisquer estruturas agregadas que possa ter).

Outras dicas

(pode ser tarde demais para responder, mas pode ser útil para outras pessoas)

Estou desenvolvendo meu primeiro sistema com JPA agora.Infelizmente, enfrento esse problema quando o sistema está quase completo.

Simplificando.Use o Hibernate ou aguarde o JPA 2.0.

No Hibernate, você pode usar 'session.evict(object)' para remover um objeto da sessão.Em JPA 2.0, em rascunho agora, existe o método 'EntityManager.detach(object)' para separar um objeto do contexto de persistência.

Não importa qual implementação JPA você usa, basta usar entityManager.detach(object) agora está no JPA 2.0 e faz parte do JEE6.

Se você precisar desanexar um objeto do EntityManager e estiver usando o Hibernate como camada ORM subjacente, poderá obter acesso ao Sessão de hibernação objeto e usar o Sessão.evict(Objeto) método que Mauricio Kanada mencionou acima.

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

É claro que isso seria interrompido se você mudasse para outro provedor de ORM, mas acho que isso é preferível a tentar fazer uma cópia profunda.

Pelo que eu sei, as únicas maneiras diretas de fazer isso são:

  1. Confirmar o txn – Provavelmente não é uma opção razoável
  2. Limpe o contexto de persistência - EntityManager.clear() - Isso é brutal, mas limparia tudo
  3. Copie o objeto - Na maioria das vezes, seus objetos JPA são serializáveis, portanto, isso deve ser fácil (se não for particularmente eficiente).

Se estiver usando EclipseLink você também tem as opções,

Use a dica de consulta, eclipselink.maintain-cache"="false - todos os objetos retornados serão desanexados.

Use o EclipseLink JpaEntityManager copy() API para copiar o objeto na profundidade desejada.

Se não houver muitas propriedades no bean, você poderá simplesmente criar uma nova instância e definir todas as suas propriedades manualmente a partir do bean persistente.

Isso poderia ser implementado como um construtor de cópia, por exemplo:

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

Então:

Thing newBean = new Thing(oldBean);

isso é rápido e sujo, mas você também pode serializar e desserializar o objeto.

Como estou usando SEAM e JPA 1.0 e meu sistema tem uma funcionalidade que precisa registrar todas as alterações de campos, criei um objeto de valor ou objeto de transferência de dados se forem os mesmos campos da entidade que precisa ser registrada.O construtor do novo 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();
            }
        }
    }
}

No JPA 1.0 (testado usando EclipseLink) você poderia recuperar a entidade fora de uma transação.Por exemplo, com transações gerenciadas por contêiner você poderia fazer:

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

Para lidar com um caso semelhante, criei um objeto DTO que estende o objeto de entidade persistente da seguinte maneira:

class MyEntity
{
   public static class MyEntityDO extends MyEntity {}

}

Finalmente, uma consulta escalar recuperará os atributos não gerenciados desejados:

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

Se você chegou aqui porque realmente deseja passar uma entidade através de um limite remoto, basta inserir algum código para enganar o hibernazi.

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

Cloneable não funcionará porque na verdade copia o PersistantBag.

E esqueça de usar fluxos serializáveis ​​e bytearray e fluxos canalizados.criar threads para evitar impasses mata todo o conceito.

Acho que existe uma maneira de expulsar uma única entidade do EntityManager chamando isso

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

Isso removerá uma entidade específica do cache.

Acho que você também pode usar o método EntityManager.refresh(Object o) se a chave primária da entidade não tiver sido alterada.Este método irá restaurar o estado original da entidade.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top