Question

Quel serait le moyen le plus simple de détacher un JPA Entity Bean spécifique acquis via un EntityManager.Alternativement, pourrais-je demander à une requête de renvoyer des objets détachés en premier lieu afin qu'ils agissent essentiellement en « lecture seule » ?

La raison pour laquelle je veux faire cela est parce que je veux modifier les données dans le bean - avec mon application uniquement, mais sans jamais les conserver dans la base de données.Dans mon programme, je dois éventuellement appeler flush() sur EntityManager, ce qui conserverait toutes les modifications des entités attachées à la base de données sous-jacente, mais je souhaite exclure des objets spécifiques.

Était-ce utile?

La solution

Malheureusement, il n'existe aucun moyen de déconnecter un objet du gestionnaire d'entités dans l'implémentation actuelle de JPA, AFAIR.

EntityManager.clear() se déconnectera tous les objets JPA, ce qui pourrait ne pas être une solution appropriée dans tous les cas, si vous avez d'autres objets que vous envisagez de garder connectés.

Votre meilleur choix serait donc de cloner les objets et de transmettre les clones au code qui modifie les objets.Étant donné que les champs d'objets primitifs et immuables sont correctement pris en charge par le mécanisme de clonage par défaut, vous n'aurez pas à écrire beaucoup de code de plomberie (à part le clonage en profondeur de toutes les structures agrégées que vous pourriez avoir).

Autres conseils

(il est peut-être trop tard pour répondre, mais cela peut être utile à d'autres)

Je développe actuellement mon premier système avec JPA.Malheureusement, je suis confronté à ce problème alors que ce système est presque terminé.

Tout simplement.Utilisez Hibernate ou attendez JPA 2.0.

Dans Hibernate, vous pouvez utiliser « session.evict(object) » pour supprimer un objet de la session.Dans JPA2.0, en projet en ce moment, il existe la méthode 'EntityManager.detach(object)' pour détacher un objet du contexte de persistance.

Quelle que soit l'implémentation JPA que vous utilisez, utilisez simplement entityManager.detach(object) c'est maintenant dans JPA 2.0 et fait partie de JEE6.

Si vous devez détacher un objet d'EntityManager et que vous utilisez Hibernate comme couche ORM sous-jacente, vous pouvez accéder au Session d'hibernation objet et utiliser le Session.evict (Objet) méthode que Mauricio Kanada a mentionnée ci-dessus.

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

Bien sûr, cela échouerait si vous passiez à un autre fournisseur ORM, mais je pense qu'il est préférable d'essayer de faire une copie complète.

Pour autant que je sache, les seuls moyens directs de le faire sont :

  1. Valider le txn - Ce n'est probablement pas une option raisonnable
  2. Effacer le contexte de persistance - EntityManager.clear() - C'est brutal, mais cela l'effacerait
  3. Copiez l'objet - La plupart du temps, vos objets JPA sont sérialisables, cela devrait donc être facile (voire particulièrement efficace).

Si vous utilisez EclipseLink vous avez aussi les options,

Utilisez l'indice de requête, eclipselink.maintain-cache"="false - tous les objets retournés seront détachés.

Utilisez le EclipseLink JpaEntityManager copy() API pour copier l'objet à la profondeur souhaitée.

S'il n'y a pas trop de propriétés dans le bean, vous pouvez simplement créer une nouvelle instance et définir toutes ses propriétés manuellement à partir du bean persistant.

Cela pourrait être implémenté en tant que constructeur de copie, par exemple :

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

Alors:

Thing newBean = new Thing(oldBean);

c'est rapide et sale, mais vous pouvez également sérialiser et désérialiser l'objet.

Étant donné que j'utilise SEAM et JPA 1.0 et que mon système a une fonctionnalité qui doit enregistrer toutes les modifications de champs, j'ai créé un objet de valeur ou un objet de transfert de données si les mêmes champs de l'entité doivent être enregistrés.Le constructeur du nouveau pojo est :

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

Dans JPA 1.0 (testé avec EclipseLink), vous pouvez récupérer l'entité en dehors d'une transaction.Par exemple, avec les transactions gérées par conteneur, vous pouvez :

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

Traitez un cas similaire. J'ai créé un objet DTO qui étend l'objet entité persistante comme suit :

class MyEntity
{
   public static class MyEntityDO extends MyEntity {}

}

Enfin, une requête scalaire récupérera les attributs non gérés souhaités :

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

Si vous arrivez ici parce que vous voulez réellement faire passer une entité à travers une frontière distante, il vous suffit de mettre du code pour tromper les hibernazis.

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

Cloneable ne fonctionnera pas car il copie en fait le PersistantBag.

Et oubliez d’utiliser des flux sérialisables et bytearray et des flux redirigés.créer des threads pour éviter les blocages tue tout le concept.

Je pense qu'il existe un moyen d'expulser une seule entité d'EntityManager en appelant ceci

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

Cela supprimera une entité particulière du cache.

Je pense que vous pouvez également utiliser la méthode EntityManager.refresh(Object o) si la clé primaire de l'entité n'a pas été modifiée.Cette méthode restaurera l'état d'origine de l'entité.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top