-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Exception: EvaluationException
PostPosted: Wed Mar 08, 2006 4:53 pm 
Newbie

Joined: Wed Mar 08, 2006 4:45 pm
Posts: 5
Hallo Leute,

hab ein Problem mit Hibernate. Und zwar benutze ich Hibernate 3 in meiner JSF Tomcat Anwendung.
Wenn ich auf der Seite ein Objekt abspeichere mit UpdateOrSave tritt die Exeption auf:

javax.faces.el.EvaluationException: java.lang.RuntimeException: a different object with the same identifier value was already associated with the session: [de.dts.tm.hibernate.document.DocumentText#1]


Kann man mit den Infermation sagen woran das liegen kann? Oder braucht ihr den Sourccode?


Vielen Dank


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 08, 2006 6:49 pm 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
wenn ich das richtige deute liegt das an einen etwas verdrehtem Session-Handling.
Du hast z.B. ein 'DocumentText' (A) mit einem bestimmten Identifier aus der DB geladen und versuchst nun eine andere Instanz von 'DocumentText' (B) mit gleicher ID wie 'A' über die gleiche Session zu speichern.
Das geht schief, da Hibernate eine Objektidentität (bezogen auf eine Session) sicher stellt.

Wieso erstellt Du überhaupt eine neue Instanz? Soll sie den gleichen Identifier haben? War das vielleicht ein versehen?

Gibt zwar eine ganz einfache Möglichkeit zu verhindern, dass diese Fehlermeldung kommt ('merge') aber ich würde Dir trotzdem raten Deine Applikation mal in Bezug auf Session-Handling durchzusehen.

HiH
curio


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 09, 2006 4:10 am 
Newbie

Joined: Wed Mar 08, 2006 4:45 pm
Posts: 5
Mhhh weiss ich auch nicht genau ... bin noch Anfänger was Hibernate angeht.
Ich Poste mal was von Sourcecode vielleicht kann mir einer sagen was ich mit der Session anders machen muss.

Das ist die Function die abspeichern versucht.
Code:
  public String doActionSaveTranslation() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        UIForm rootForm = (UIForm) facesContext.getViewRoot().getChildren().get(0);

        HtmlPanelGrid panelGrid = null;
        Iterator it = rootForm.getChildren().iterator();
        if (it != null) {
            while (it.hasNext()) {
                Object x = it.next();
                if (x instanceof HtmlPanelGrid) {
                    panelGrid = (HtmlPanelGrid) x;
                    break;
                }
            }

            List panelGridChildren = panelGrid.getChildren();

            Iterator panelGridIter = panelGridChildren.iterator();
            while (panelGridIter.hasNext()) {
                Object object = panelGridIter.next();

                if (object instanceof HtmlInputTextarea) {
                    HtmlInputTextarea htmlTextArea = (HtmlInputTextarea) object;
                    String id = htmlTextArea.getId();
                    if (id != null) {
                        if (id.startsWith("doc")) {
                            String tag = id.substring(3, id.length());
                            Iterator docTextIter = getEditDocument().getText().
                                    iterator();
                            if (docTextIter != null) {
                                Boolean foundTag = false;
                                while (docTextIter.hasNext()) {
                                    DocumentText docText = (DocumentText)docTextIter.next();
                                    if (docText != null) {
                                        if (tag.equals(docText.getTag())) {
                                            String value = htmlTextArea.getValue().toString();
                                            docText.setText(value);
                                            qm.updateOrSave(docText);
                                            foundTag = true;
                                        }
                                    }
                                }
                                if (!foundTag) {
                                    DocumentText newDocText = new DocumentText();
                                    newDocText.setText(htmlTextArea.getValue().toString());
                                    newDocText.setTag(tag);
                                    newDocText.setIsComplete(0);
                                    newDocText.setDocument_ID(getEditDocument().getId());
                                    qm.updateOrSave(newDocText);
                                }
                            }
                        }
                    }

                }

            }
        }
        return "doSave";
    }


Die Funktion holt das Document mti denn DocumentText als Set

Code:
    public String getDocumentName() {
System.out.println(" ##### getDocumentName()");
        Map session = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
        int docId = (Integer)session.get("selectedDocID");
        Documents document=null;
        try {
            document = qm.findDocumentByID(docId);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if(document !=null) {
System.out.println("  setEditDocument(" + document + ")");
            setEditDocument(document);
            documentName = document.getDocName();
        }else
            return "Error";
        pdfPreviewName= documentName;
        return documentName;
    }




Das sind die Hibernate querys in der Klasse QueryManager:
Code:
   public Documents findDocumentByID(int id) throws Exception {
      Session session = null;
      Transaction tx = null;
      session = HibernateSessionFactory.currentSession();
      tx = session.beginTransaction();

      Iterator result=null;
    try{
        Query q = session.createQuery("FROM " + Documents.class.getName() +" as d WHERE d.id = :id");
        q.setInteger("id",id);
        result = q.iterate();
        tx.commit();
    }catch(Exception e) {
            e.printStackTrace();
    } finally {
        if (result.hasNext()) {
            Documents doc = (Documents) result.next();
            return doc;
        } else {
            throw new Exception("Documents can't be find");
        }
    }
  }



Das ist die Funktion die die Objecte abspeichert:
Code:
  public void updateOrSave(Object document) {
         Session session = null;
         Transaction tx = null;

       try {
           session = HibernateSessionFactory.currentSession();
           tx = session.beginTransaction();

           session.saveOrUpdate(document);

           tx.commit();
       } catch (HibernateException ex) {
           session.close();
           if (tx != null)
               try {
                   tx.rollback();
               } catch (HibernateException exRb) {}
           throw new RuntimeException(ex.getMessage());
       }
    }



Und das ist der SessionHandler
Code:

public class HibernateSessionFactory {


    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";

    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();

    private static final Configuration cfg = new Configuration();

    private static org.hibernate.SessionFactory sessionFactory;


    public static Session currentSession() throws HibernateException {
        Session session = (Session) threadLocal.get();

        if (session != null && ! session.isConnected())
                session = null;
        if (session == null) {
            if (sessionFactory == null) {
                try {
                    cfg.configure(CONFIG_FILE_LOCATION);
                    sessionFactory = cfg.buildSessionFactory();
                }
                catch (Exception e) {
                    System.err.println("%%%% Error Creating SessionFactory %%%%");
                    e.printStackTrace();
                }
            }
            session = sessionFactory.openSession();
            threadLocal.set(session);
        }
//        System.out.println(" ### Aktuelle SESSION: "+session);
        return session;
    }

    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);

        if (session != null) {
            session.close();
        }
    }

    private HibernateSessionFactory() {
    }

}




Ich hoffe ihr könnt mir helfen ich verzweifle schon


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 09, 2006 5:22 am 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
Hibernate stellt in Bezug auf eine Session "Instanzengleichheit" sicher. D.h. dass Du nicht 2 Instanzen eines Objektes mit gleicher ID über eine Session verwalten kannst. Das führt zu dem obigen Fehler.

Du erzeugst Dir ja nun ganz offensichtlich eine neue Instanz von "DocumentText". Nun musst Du wissen, ob das wirklich etwas neues ist (insert) oder ob es aktualisiert werden soll (update).

Wenn es nichts neues ist, stellt sich mir die Frage warum Du die geladene DocumentText-Instanz nicht aufhebst und dort die Änderungen einträgst. Dann hättest Du das Problem nicht.

Alternativ kannst Du Deine DocumentText-Instanz mit 'evict' auch aus der Session entfernen, dann kommt der Fehler auch nicht.

Aber für's Protokoll, sofern die ID von DocumentText ein technischer Schlüssel ist: Diesen Wert solltest Du NIE in der Applikation selbst setzen! Das führt im Zweifelsfall zu bösen Fehlern, die man sogut wie schlecht ;) findet.

Mal so grob und schnell. Das Beste wird sein, wenn Du die Hib-Doku eimal durchliest ... da ist das alles sehr gut erklärt! Und vielleicht mit einem einfacheren Beispiel anfängst, wo Du Dich ganz auf Hib konzentrieren kannst.

Auch 'Hibernate in Action' kann ich nur empfehlen.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 09, 2006 6:01 am 
Newbie

Joined: Wed Mar 08, 2006 4:45 pm
Posts: 5
Aber wieso meinst du das ich eine neue Instanz von DocumentText mache?

Code:
while (docTextIter.hasNext()) {
                                    DocumentText docText = (DocumentText)docTextIter.next();
                                    if (docText != null) {
                                        if (tag.equals(docText.getTag())) {
                                            String value = htmlTextArea.getValue().toString();
                                            docText.setText(value);
                                            qm.updateOrSave(docText);
                                            foundTag = true;
                                        }
                                    }
                                }


Hier "DocumentText docText = (DocumentText)docTextIter.next();" hole ich mir ja DocumentText raus wenn es schon existiert und erstell kein neues.

Ich erstell ein neues wenn es in der Datenbank noch nicht existiert.

Und zweites: Wann ist es sinnvoll einen flush oder sogar die Session zu closen?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 09, 2006 6:43 am 
Expert
Expert

Joined: Tue Oct 05, 2004 9:45 am
Posts: 263
Quote:
Aber wieso meinst du das ich eine neue Instanz von DocumentText mache?

Weil das der Grund ist, warum die Fehlermeldung kommt :) Du versuchst eine andere Instanz, mit gleicher ID über die gleiche Session zu speichern.
Warum das passiert kann ich Dir nicht sagen, da müsstest Du Dir die Abläufe Deiner Applikation anschauen.

Was das schliessen der Session angeht, kann ich Dir das auch nicht so pauschal sagen. Kommt drauf an, was Du damit vor hast. Generell ist wohl das "OpenSessionInViewPattern" keine schlechte Wahl, sofern Dir das genügt. Gibt hier sehr gute Doku und Beispiele dazu - einfach mal durch die Doku auf 'hibernate.org' blättern.

Flushen, commiten solltest Du immer, wenn Du was wirklich in der Datenbank haben willst. Wie gesagt: Am besten mal die Hibernate-Doku durcharbeiten.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.