Domanda

Quale sarebbe il modo più semplice per staccare uno specifico Entity Bean JPA acquisito tramite un EntityManager.In alternativa, potrei fare in modo che una query restituisca innanzitutto oggetti scollegati in modo che agiscano essenzialmente come "sola lettura"?

Il motivo per cui voglio farlo è perché voglio modificare i dati all'interno del bean, solo nella mia applicazione, ma non mantenerli mai nel database.Nel mio programma, alla fine devo chiamare flush() su EntityManager, che persisterebbe tutte le modifiche dalle entità collegate al database sottostante, ma voglio escludere oggetti specifici.

È stato utile?

Soluzione

Sfortunatamente, non c'è modo di disconnettere un oggetto dal gestore entità nell'attuale implementazione JPA, AFAIR.

EntityManager.clear() si disconnetterà Tutto gli oggetti JPA, quindi potrebbe non essere una soluzione appropriata in tutti i casi, se hai altri oggetti che prevedi di mantenere connessi.

Quindi la soluzione migliore sarebbe clonare gli oggetti e passare i cloni al codice che modifica gli oggetti.Poiché i campi oggetto primitivi e immutabili sono gestiti dal meccanismo di clonazione predefinito in modo corretto, non dovrai scrivere molto codice idraulico (a parte la clonazione profonda di eventuali strutture aggregate che potresti avere).

Altri suggerimenti

(potrebbe essere troppo tardi per rispondere, ma può essere utile per altri)

Sto sviluppando il mio primo sistema con JPA proprio adesso.Sfortunatamente mi trovo ad affrontare questo problema quando il sistema è quasi completo.

In poche parole.Utilizza l'ibernazione o attendi JPA 2.0.

In Hibernate, puoi usare 'session.evict(object)' per rimuovere un oggetto dalla sessione.In APP 2.0, in bozza in questo momento, esiste il metodo 'EntityManager.detach(object)' per staccare un oggetto dal contesto di persistenza.

Non importa quale implementazione JPA usi, usa e basta entityManager.detach(object) ora è in JPA 2.0 e fa parte di JEE6.

Se hai bisogno di scollegare un oggetto da EntityManager e stai utilizzando Hibernate come livello ORM sottostante, puoi accedere a Sessione di ibernazione oggetto e utilizzare il Session.evict(Oggetto) metodo menzionato sopra da Mauricio Kanada.

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

Ovviamente questo si romperebbe se passassi a un altro provider ORM, ma penso che sia preferibile provare a fare una copia approfondita.

Per quanto ne so, gli unici modi diretti per farlo sono:

  1. Impegna il txn - Probabilmente non è un'opzione ragionevole
  2. Cancella il contesto di persistenza - EntityManager.clear() - Questo è brutale, ma lo cancellerebbe
  3. Copia l'oggetto: la maggior parte delle volte i tuoi oggetti JPA sono serializzabili, quindi dovrebbe essere facile (se non particolarmente efficiente).

Se si utilizza EclipseLink hai anche le opzioni,

Utilizza il suggerimento per la query, eclipselink.maintain-cache"="false - tutti gli oggetti restituiti verranno staccati.

Usa il EclipseLink JpaEntityManager copy() API per copiare l'oggetto alla profondità desiderata.

Se non ci sono troppe proprietà nel bean, potresti semplicemente creare una nuova istanza e impostare manualmente tutte le sue proprietà dal bean persistente.

Questo potrebbe essere implementato come un costruttore di copie, ad esempio:

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

Poi:

Thing newBean = new Thing(oldBean);

questo è veloce e sporco, ma puoi anche serializzare e deserializzare l'oggetto.

Poiché utilizzo SEAM e JPA 1.0 e il mio sistema ha una funzionalità che deve registrare tutte le modifiche dei campi, ho creato un oggetto valore o un oggetto di trasferimento dati se sono gli stessi campi dell'entità che devono essere registrati.Il costruttore del nuovo 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();
            }
        }
    }
}

In JPA 1.0 (testato utilizzando EclipseLink) è possibile recuperare l'entità al di fuori di una transazione.Ad esempio, con le transazioni gestite dal contenitore potresti fare:

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

Affronta un caso simile, ho creato un oggetto DTO che estende l'oggetto entità persistente come segue:

class MyEntity
{
   public static class MyEntityDO extends MyEntity {}

}

Infine, una query scalare recupererà gli attributi non gestiti desiderati:

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

Se arrivi qui perché vuoi effettivamente far passare un'entità attraverso un confine remoto, allora inserisci semplicemente del codice per ingannare l'ibernazione.

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

Cloneable non funzionerà perché copia effettivamente il PersistantBag.

E dimentica di utilizzare flussi serializzabili e bytearray e flussi convogliati.la creazione di thread per evitare stalli uccide l'intero concetto.

Penso che ci sia un modo per sfrattare una singola entità da EntityManager chiamandolo

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

Ciò rimuoverà una particolare entità dalla cache.

Penso che tu possa anche usare il metodo EntityManager.refresh(Object o) se la chiave primaria dell'entità non è stata modificata.Questo metodo ripristinerà lo stato originale dell'entità.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top