Pregunta

¿Cuál sería la forma más sencilla de separar un Bean de entidad JPA específico que se adquirió a través de un EntityManager?Alternativamente, ¿podría hacer que una consulta devuelva objetos separados en primer lugar para que esencialmente actúen como "solo lectura"?

La razón por la que quiero hacer esto es porque quiero modificar los datos dentro del bean, solo en mi aplicación, pero nunca persistir en la base de datos.En mi programa, eventualmente tengo que llamar a Flush() en EntityManager, lo que persistiría todos los cambios de las entidades adjuntas a la base de datos subyacente, pero quiero excluir objetos específicos.

¿Fue útil?

Solución

Desafortunadamente, no hay manera de desconectar un objeto del administrador de entidades en la implementación actual de JPA, AFAIR.

EntityManager.clear() se desconectará todo los objetos JPA, por lo que podría no ser una solución adecuada en todos los casos, si tiene otros objetos que planea mantener conectados.

Entonces, lo mejor sería clonar los objetos y pasar los clones al código que cambia los objetos.Dado que el mecanismo de clonación predeterminado se ocupa de los campos de objetos primitivos e inmutables de manera adecuada, no tendrá que escribir mucho código de plomería (aparte de la clonación profunda de cualquier estructura agregada que pueda tener).

Otros consejos

(puede que sea demasiado tarde para responder, pero puede ser útil para otros)

Estoy desarrollando mi primer sistema con JPA en este momento.Desafortunadamente me enfrento a este problema cuando este sistema está casi completo.

Simplemente pon.Utilice Hibernar o espere a JPA 2.0.

En Hibernate, puedes usar 'session.evict(object)' para eliminar un objeto de la sesión.En APP 2.0, en borrador ahora mismo, existe el método 'EntityManager.detach(object)' para separar un objeto del contexto de persistencia.

No importa qué implementación JPA uses, solo usa entityManager.detach(object) ahora está en JPA 2.0 y forma parte de JEE6.

Si necesita separar un objeto del EntityManager y está utilizando Hibernate como capa ORM subyacente, puede obtener acceso al Hibernar sesión objeto y utilizar el Sesión.desalojar(Objeto) método que Mauricio Kanada mencionó anteriormente.

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

Por supuesto, esto se rompería si cambiara a otro proveedor de ORM, pero creo que es preferible intentar hacer una copia profunda.

Hasta donde yo sé, las únicas formas directas de hacerlo son:

  1. Confirmar el txn: probablemente no sea una opción razonable
  2. Borrar el contexto de persistencia - EntityManager.clear() - Esto es brutal, pero lo borraría
  3. Copie el objeto: la mayoría de las veces sus objetos JPA son serializables, por lo que esto debería ser fácil (aunque no particularmente eficiente).

Si usa EclipseLink también tienes las opciones,

Utilice la sugerencia de consulta, eclipselink.maintain-cache"="false - todos los objetos devueltos serán separados.

Utilizar el EclipseLink JpaEntityManager copy() API para copiar el objeto a la profundidad deseada.

Si no hay demasiadas propiedades en el bean, puede simplemente crear una nueva instancia y configurar todas sus propiedades manualmente desde el bean persistente.

Esto podría implementarse como un constructor de copias, por ejemplo:

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

Entonces:

Thing newBean = new Thing(oldBean);

Esto es rápido y sucio, pero también puedes serializar y deserializar el objeto.

Como estoy usando SEAM y JPA 1.0 y mi sistema tiene una funcionalidad que necesita registrar todos los cambios de campos, he creado un objeto de valor u objeto de transferencia de datos si son los mismos campos de la entidad que deben registrarse.El constructor del nuevo pojo es:

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

En JPA 1.0 (probado con EclipseLink), se podía recuperar la entidad fuera de una transacción.Por ejemplo, con transacciones administradas por contenedores podría hacer:

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 tratar un caso similar, he creado un objeto DTO que extiende el objeto de entidad persistente de la siguiente manera:

class MyEntity
{
   public static class MyEntityDO extends MyEntity {}

}

Finalmente, una consulta escalar recuperará los atributos no administrados deseados:

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

Si llegas aquí porque realmente quieres pasar una entidad a través de un límite remoto, entonces simplemente ingresas un código para engañar a los hibernazi.

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

Cloneable no funcionará porque en realidad copia el PersistantBag.

Y olvídese de utilizar flujos serializables y de bytearray y flujos canalizados.Crear hilos para evitar puntos muertos acaba con todo el concepto.

Creo que hay una manera de desalojar una sola entidad de EntityManager llamando a esto

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

Esto eliminará una entidad particular del caché.

Creo que también puedes usar el método EntityManager.refresh(Object o) si no se ha cambiado la clave principal de la entidad.Este método restaurará el estado original de la entidad.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top