Frage

Was wäre der einfachste Weg, ein bestimmtes JPA-Entity-Bean zu trennen, das über einen EntityManager erworben wurde?Könnte ich alternativ eine Abfrage veranlassen, getrennte Objekte überhaupt zurückzugeben, sodass sie im Wesentlichen als „schreibgeschützt“ fungieren?

Der Grund, warum ich dies tun möchte, ist, dass ich die Daten innerhalb der Bean ändern möchte – nur in meiner Anwendung, sie aber nie in der Datenbank beibehalten lassen.In meinem Programm muss ich schließlich „flush()“ für den EntityManager aufrufen, wodurch alle Änderungen von angehängten Entitäten in der zugrunde liegenden Datenbank beibehalten werden, ich möchte jedoch bestimmte Objekte ausschließen.

War es hilfreich?

Lösung

Leider gibt es in der aktuellen JPA-Implementierung AFAIR keine Möglichkeit, ein Objekt vom Entitätsmanager zu trennen.

EntityManager.clear() wird die Verbindung trennen alle die JPA-Objekte, sodass dies möglicherweise nicht in allen Fällen eine geeignete Lösung ist, wenn Sie andere Objekte haben, die Sie verbinden möchten.

Am besten klonen Sie also die Objekte und übergeben die Klone an den Code, der die Objekte ändert.Da primitive und unveränderliche Objektfelder vom standardmäßigen Klonmechanismus ordnungsgemäß behandelt werden, müssen Sie nicht viel Installationscode schreiben (abgesehen vom tiefen Klonen eventuell vorhandener aggregierter Strukturen).

Andere Tipps

(Vielleicht ist es zu spät für eine Antwort, kann aber für andere nützlich sein.)

Ich entwickle gerade mein erstes System mit JPA.Leider stehe ich vor diesem Problem, wenn dieses System fast fertig ist.

Einfach gesagt.Verwenden Sie den Ruhezustand oder warten Sie auf JPA 2.0.

Im Ruhezustand können Sie „session.evict(object)“ verwenden, um ein Objekt aus der Sitzung zu entfernen.In JPA 2.0, gerade im Entwurf, Es gibt die Methode „EntityManager.detach(object)“, um ein Objekt vom Persistenzkontext zu trennen.

Egal welche JPA-Implementierung Sie verwenden, verwenden Sie einfach entityManager.detach(object) es ist jetzt in JPA 2.0 und Teil von JEE6.

Wenn Sie ein Objekt vom EntityManager trennen müssen und Hibernate als zugrunde liegende ORM-Ebene verwenden, können Sie darauf zugreifen Ruhezustandssitzung Objekt und verwenden Sie die Session.evict(Objekt) Methode, die Mauricio Kanada oben erwähnt hat.

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

Natürlich würde dies nicht funktionieren, wenn Sie zu einem anderen ORM-Anbieter wechseln würden, aber ich denke, dass dies besser ist als der Versuch, eine tiefe Kopie zu erstellen.

Soweit ich weiß, sind die einzigen direkten Möglichkeiten, dies zu tun:

  1. Commit the txn – Wahrscheinlich keine vernünftige Option
  2. Löschen Sie den Persistenzkontext – EntityManager.clear() – Das ist brutal, würde es aber beseitigen
  3. Kopieren Sie das Objekt – Meistens sind Ihre JPA-Objekte serialisierbar, daher sollte dies einfach (wenn auch nicht besonders effizient) sein.

Bei Verwendung EclipseLink Sie haben auch die Möglichkeiten,

Verwenden Sie den Abfragehinweis. eclipselink.maintain-cache"="false - Alle zurückgegebenen Objekte werden abgetrennt.

Benutzen Sie die EclipseLink JpaEntityManager copy() API zum Kopieren des Objekts in die gewünschte Tiefe.

Wenn die Bean nicht zu viele Eigenschaften enthält, können Sie einfach eine neue Instanz erstellen und alle ihre Eigenschaften manuell über die persistente Bean festlegen.

Dies könnte beispielsweise als Kopierkonstruktor implementiert werden:

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

Dann:

Thing newBean = new Thing(oldBean);

Das geht zwar schnell, aber Sie können das Objekt auch serialisieren und deserialisieren.

Da ich SEAM und JPA 1.0 verwende und mein System über eine Funktion verfügt, die alle Feldänderungen protokollieren muss, habe ich ein Wertobjekt oder Datenübertragungsobjekt für dieselben Felder der Entität erstellt, die protokolliert werden muss.Der Konstruktor des neuen Pojo ist:

    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 (getestet mit EclipseLink) konnten Sie die Entität außerhalb einer Transaktion abrufen.Mit Container-verwalteten Transaktionen könnten Sie beispielsweise Folgendes tun:

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

Um einen ähnlichen Fall zu behandeln, habe ich ein DTO-Objekt erstellt, das das persistente Entitätsobjekt wie folgt erweitert:

class MyEntity
{
   public static class MyEntityDO extends MyEntity {}

}

Schließlich ruft eine Skalarabfrage die gewünschten nicht verwalteten Attribute ab:

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

Wenn Sie hierher kommen, weil Sie eine Entität tatsächlich über eine entfernte Grenze weiterleiten möchten, fügen Sie einfach Code ein, um den Hibernazi auszutricksen.

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

Cloneable funktioniert nicht, da es tatsächlich den PersistantBag kopiert.

Und vergessen Sie die Verwendung von serialisierbaren und Bytearray-Streams sowie Piped-Streams.Das Erstellen von Threads zur Vermeidung von Deadlocks macht das gesamte Konzept zunichte.

Ich denke, es gibt eine Möglichkeit, eine einzelne Entität aus EntityManager zu entfernen, indem Sie dies aufrufen

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

Dadurch wird eine bestimmte Entität aus dem Cache entfernt.

Ich denke, Sie können die Methode EntityManager.refresh(Object o) auch verwenden, wenn der Primärschlüssel der Entität nicht geändert wurde.Diese Methode stellt den ursprünglichen Zustand der Entität wieder her.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top