-->
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.  [ 5 posts ] 
Author Message
 Post subject: Objekt zeigt falsche Referenzen an...
PostPosted: Wed Apr 07, 2010 2:34 am 
Newbie

Joined: Sun Jan 01, 2006 1:39 pm
Posts: 15
Hallo,

ich habe ein Problem in meiner Web Anwendung mit Hibernate 3.0. Nach dem Speichern eines neuen Objektes und dem anschließenden Aufrufen werden teilweise falsche Referenzen angezeigt.

Ich beschreibe erst einmal beispielhaft die Objektherachie:

"Hersteller"
- Id
- Name
- Ort
-...

"Arbeitsgang"
- Id
- Name
- ...

"Fenster"
- Id
- Name
- Größe
- Arbeitsgang (Referenz zum Objekt Arbeitsgang)
- Hersteller (Referenz zum Objekt Hersteller)
- ...

Auszugsweise die hbm.xml Dateien dazu:

Fenster:
Code:
<id name="id" column="ID" type="java.lang.Long" unsaved-value="null">
         <generator class="identity">
         </generator>
</id>
      
<many-to-one class="com.test.Arbeitsgang" fetch="select"
   insert="false" lazy="false" name="arbeitsgang" update="false">
   <column name="arbeitsgangId" scale="0"/>
  </many-to-one>
 
  <property generated="never" lazy="false" name="arbeitsgangId" type="java.lang.Long">
   <column name="arbeitsgangId" not-null="false" scale="0"/>
  </property>
 
  <many-to-one class="com.test.Hersteller" fetch="select"
   insert="false" lazy="false" name="hersteller" update="false">
   <column name="herstellerId" scale="0"/>
  </many-to-one>
   ....



Arbeitsgang:
Code:
   <id name="id" column="ID" type="java.lang.Long" unsaved-value="null">
         <generator class="identity">
         </generator>
  </id>
... (restlichen Entitäten sind uninteressant)


Hersteller:
Code:
  <id name="id" column="ID" type="java.lang.Long" unsaved-value="null">
         <generator class="identity">
         </generator>
</id>
... (restlichen Entitäten sind uninteressant)


Ich erstelle ein neues Fensterobjekt und weise dem ein bestehendes Hersteller- und Arbeitsgangobjekt zu. Anschließend speichere ich das Fensterobjekt:
Code:
Session session = openSession(); // Funktion um eine Session über eine SessionFactory zu erstellen / öffnen

      try {
         beginTransaction(session);
         session.save(transientInstance);
         
         commit();
         
         log.debug("save successful");
      } catch (RuntimeException re) {
         log.error("get failed", re);
         throw re;
      }finally {
         closeSession();
      }

Als nächstes hole ich mir direkt die Fensterobjekte anhand eines Arbeitsganges (Id):
Code:
Session session = openSession();      
      try {
         beginTransaction(session);
         
         Fenster instance = null;         
         String sql = "from Fenster as f LEFT OUTER JOIN f.hersteller LEFT OUTER JOIN f.arbeitsgang WHERE f.arbeitsgangId="+id;
         Query query = session.createQuery(sql);
                  
         Iterator it = query.list().iterator();
         while(it.hasNext()){
            Object[] o = (Object[]) it.next();
            Fenster fenster = (Fenster) o[0];
         
            instance = fenster;
         }
         
         commit();
         return instance;
      } catch (RuntimeException re) {
         log.error("get failed", re);
         throw re;
      }finally {
         closeSession();
      }

Und jetzt zu dem Problem. In der Datenbank werden die Objekte richtig gespeichert; jeder Fensterdatensatz referenziert richtig auf den Hersteller und auch auf dem Arbeitsgang. Wenn ich mir die Datensätze in meiner Webanwendung mit der zuvor beschrieben Methode anzeigen lassen (auch im Debug Modus), sehe ich dass manche Fensterobjekte einen Arbeitsgang an Board haben, und manche nicht. Stoppe ich den Tomcat und starte ihn wieder, werden mir die Referenzen richtig angezeigt. Mir kommt es so vor als hätte ich ein Caching Problem. Wo dran könnte das liegen?

Noch eine Kleinigkeit. Die Fensterklasse hat jeweils die Arbeitsgang- und die Herstellerklasse an Board. Auch wenn die Referenzen falsch sind, könnte ich durch das Iterieren in der Liste auf die anderen Objekte zugreifen:
Code:
while(it.hasNext()){
            Object[] o = (Object[]) it.next();
            Fenster fenster = (Fenster) o[0];
            Hersteller hersteller = (Hersteller) o[1]; // Dieses Objekt wurde richtig zugewiesen
            Arbeitsgang arbeitsgang = (Arbeitsgang) o[2]; // Auch dieses Objekt wurde richtig zugewiesen
            instance = fenster;
         }


Aber ich möchte ja nicht immer über die gesamte Liste iterieren um an die richtigen Objekte zu kommen, dass müßte auch ohne klappen, oder?

Hoffentlich versteht man mein Problem.

Vielen Dank für Eure Hilfe.

Daniel


Top
 Profile  
 
 Post subject: Re: Objekt zeigt falsche Referenzen an...
PostPosted: Wed Apr 07, 2010 7:43 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Quote:
Mir kommt es so vor als hätte ich ein Caching Problem. Wo dran könnte das liegen?


Also deiner Beschreibung nach, sieht es aus als wuerde folgendes Schenario passieren:
Code:
Fenster transientInstance = new Fenster();
Hersteller hersteller = // nicht null ...
Arbeitsgang arbeitsgang =  // nicht null ....
transientInstance.setHersteller(hersteller);
transientInstance.setArbeitsGang(arbeitsgang);
...
session.save(transientInstance);
commit();
...
transientInstance.setHersteller(hersteller); // hersteller == null
transientInstance.setArbeitsGang(arbeitsgang); //  // arbeitsgang == null
...
Object[] o = (Object[]) it.next();
            Fenster fenster = (Fenster) o[0];
            ///           fenster.getHersteller() == null;
            Hersteller hersteller = (Hersteller) o[1]; // Dieses Objekt wurde richtig zugewiesen
           /// hersteller != null


Die Tatsache dass fenster.getHersteller() == null ist und dagegen o[1] != null
ist durch RepeatableRead-Verhalten zu erklaeren welches Hibernate internen emuliert
(abgeschaut von der Repeateble-read-isolation-level-Definition).

An Deiner Stelle wuerde ich in der methode Fenster#setHersteller() einen Breakpoint setzen und debuggen und schauen ob es Aufrufe gibt die den Hersteller auf null zuruecksetzen


Top
 Profile  
 
 Post subject: Re: Objekt zeigt falsche Referenzen an...
PostPosted: Wed Apr 07, 2010 3:27 pm 
Newbie

Joined: Sun Jan 01, 2006 1:39 pm
Posts: 15
Besten Dank fü die schnelle Antwort.

Ich habe es versucht zu debuggen. Leider wird die Methode zum Setzen des Herstellers auf NULL nicht aufgerufen. Die Methode wird nur aufgerufen wenn auch ein Arbeitsgang gesetzt wird.

Wenn ich hinterm commit ein session.clear() aufrufe, dann funktioniert alles wie es soll. Aber es kann doch nicht sein dass ich jetzt immer nach dem commiten ein clear ausführen muss.

Hast du vielleicht noch eine Idee?

Vielen Dank.


Top
 Profile  
 
 Post subject: Re: Objekt zeigt falsche Referenzen an...
PostPosted: Thu Apr 08, 2010 2:20 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Quote:
Hast du vielleicht noch eine Idee?


Falls Du die Assoziations-property nicht private declariert hast, koennte es sein,
dass irgendwer den Inhalt direkt auf null setzt ohne dabei die entsprechende setter-method aufzurufen?
(In Eclipse z.B. kann man auch breakpoints auf Variablenzuweisungen setzen !)
Kontrolliere auch ob das Fenster Object noch tatsaechlich die gleiche Referenz aus der ersten Transaction ist (sollte so sein).
Ist dem nicht so, dann solltest du auch ev. die Konstruktoren von Fenster debuggen.


Top
 Profile  
 
 Post subject: Re: Objekt zeigt falsche Referenzen an...
PostPosted: Thu Apr 08, 2010 4:42 pm 
Newbie

Joined: Sun Jan 01, 2006 1:39 pm
Posts: 15
Hallo pbooo67,

die Properties habe ich alle private deklariert. Über die Breakpoints bei der Variablendeklaration habe ich die Neuzuweisung bzw. das Setzen auf NULL auch nicht nachvollziehen können.

Ich habe mir jetzt noch einmal die hbm.xml angeschaut.

Code:
<many-to-one class="com.dv.caq.fep.bo.Arbeitsgang" fetch="select"
   insert="true" lazy="false" name="arbeitsgang" update="false">
   <column name="arbeitsGangId" scale="0"/>
  </many-to-one>
 
  <!--
  <property generated="never" lazy="false" name="arbeitsgangId" type="java.lang.Long">
   <column name="arbeitsgangId" not-null="false" scale="0"/>
  </property>
   -->


Ich hatte zu dem Objekt Arbeitsgang ja auch noch einmal die ID geholt. Das habe ich jetzt einmal auskommentiert. Dann hatte ich in der many-to-one Deklaration das insert auf false stehen. Habe ich jetzt auch auf true gesetzt.

Vorher hatte ich vor dem Speichern des Fensters die referenzierenden Objekte über die ID (fenster.setArbeitsgangId(id)) zugeordnet. Jetzt mache ich das direkt mit dem Objekt:
fenster.setArbeitsgang(arbeitsgang);
fenster.setHersteller(hersteller);
usw.

Wenn ich dann das Objekt Fenster speicher, passt alles. Die Referenzen Arbeitsgang und Hersteller sind nach dem erneuten holen aus der DB die gleichen wie vor dem Speichern (habe ich kontrolliert).

Jetzt sollte ich eigentlich glücklich sein dass es funktioniert… bin ich aber nicht ganz. Bei meiner Anwendung handelt es sich um eine Webanwendung. Ich zeige dem Benutzer Comboboxen z.B. Arbeitsgängen, Hersteller zur Auswahl an. Nach der Auswahl des Arbeitsganges kann er das Fenster speichern. Dann steht mir in der Business Logik naürlich auch nur die arbeitsgangId und die herstellerId zur Verfügung. Da ich aber das komplette Objekt benötige, muss ich erst noch einmal mehrere Datenbankstatements absetzen um an die Arbeitsgang und Hersteller Objekte zu kommen.
Es reicht auch nicht wenn ich vor der Zuweisung „fenster.setArbeitsgang(arbeitsgang);“ ein Arbeitsgang mit der id anlege und dann zuweise. Dann habe ich wieder das anfängliche Problem (Referenz auf das falsche Objekt). Oder ich cleare wieder die Session, dann holt er die Objekte neu aus der DB.

Was ist jetzt die richtige Vorgehensweise? Bzw. wozu würdest du raten:

- in der hbm.xml die id´s der Hersteller und Arbeitsgänge drin lassen und die Zuweisung dann dadrüber machen. Mit der Folge dass ich ein Session.clear() nach dem Saven durchführen muss? Oder
- die id´s aus der hbm.xml raus nehmen und die Zuweisung über die zuvor per SQL Statement bereitgestellten Objekte durchzuführen? Oder
- die Objekte Arbeitsgang und Hersteller über die ID zu erstellen und anschließend ein Session.clear() durchführen...
- oder ganz anders?

Hast du noch ein Best Practice für mich?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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.