Hibernate - 1:1 Beziehung liefert leeres Objekt

Status
Nicht offen für weitere Antworten.

y0dA

Top Contributor
Hi!
Also ich habe 2 Tabellen, welche eine 1:1 Beziehung zueinander haben. Nun besteht das Problem dass ich wenn ich einen Eintrag aus der Tabelle Feature laden möchte, ich korrekterweise auch den dazu passenden Eintrag aus der Tabelle FeatureInterconnection bekomme. Andersum funktioniert es leider nicht, da ist dann das Feature leer.

Feature hbm:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="at.pcd.wam.technologie.persistence.model">
	<class name="at.pcd.wam.technologie.persistence.model.FeatureModel"
		table="FEATURE">

		
		<id name="id" type="integer" column="F_ID">
		<generator class="assigned" />
		</id>
	
		
		<one-to-one name="fInterconModel" class="at.pcd.wam.technologie.persistence.model.FeatureInterconnectionModel"
			property-ref="featureId"/>
	
		<property name="dataSupplierSourceId" type="integer" column="F_DSS_ID" />
		<property name="featureTypeId" type="integer" column="F_FT_ID" />
		<property name="geom" type="at.pcd.wam.technologie.persistence.custom.type.JGeometryType" column="F_GEOM" />
		<property name="insert" type="timestamp" column="F_INSERT" />
		<property name="intersectionId" type="integer" column="F_INTERSECTION_ID" />
		<property name="name" type="string" column="F_NAME" />
		<property name="update" type="timestamp" column="F_UPDATE" />

	</class>
</hibernate-mapping>

FeatureInterconnection hbm:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="at.pcd.wam.technologie.persistence.model">
	<class name="at.pcd.wam.technologie.persistence.model.FeatureInterconnectionModel"
		table="FEATURE_INTERCONNECTION">

		
		<id name="id" type="integer" column="FI_ID">
		<generator class="assigned" />
		</id>
		
		
		<many-to-one name="featureId" class="at.pcd.wam.technologie.persistence.model.FeatureModel" 
         column="FI_F_ID" /> 
		
		<property name="featureFrom" type="integer" column="FI_F_FEATURE_FROM" />
		<property name="featureInterconnectionTypeId" type="integer" column="FI_FIT_ID" />
		<property name="featureTo" type="integer" column="FI_F_FEATURE_TO" />
		<property name="length" type="float" column="FI_LENGTH" />
		<property name="lengthUnit" type="string" column="FI_LENGTH_UNIT" />

	</class>
</hibernate-mapping>

Also wenn ich bspw folgendes Stmt absetze klappt alles wunderbar:
Code:
from FeatureModel t where t.id = 3277

Folgendes liefert mir leider ein Objekt mit null Einträgen:
Code:
from FeatureInterconnectionModel t where t.featureFrom = :fromId and t.featureTo = :toId
 
Ok, hat sich erübrigt!
Irgendwie kann das der Eclipse Debugger nicht so anzeigen wie ich möchte, wenn ich aber auf die Werte zugreife im Code, sind sie da.

**EDIT**
Ok, klappt wohl doch nicht so wie gewünscht.
Also ich kann dann nur auf die ID zugreifen und wenn ich auf etwas anderes zugreifen möchte, bekomme ich folgende Exception:
Code:
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
	at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
	at at.pcd.wam.technologie.persistence.model.FeatureModel$$EnhancerByCGLIB$$294ecce8.getName(<generated>)
	at at.pcd.wam.technologie.batch.Duummmy.main(Duummmy.java:18)

bei folgender Abfrage:
Code:
from FeatureInterconnectionModel t where t.featureFrom = :fromId and t.featureTo = :toId 
[code]

bei folgendem Objektzugriff:
[code]
fInterconnectionModel.getFeatureId().getName());

jener Objektzugriff funktioniert:
Code:
fInterconnectionModel.getFeatureId().getId());
 
Problem sind da die Lazy-Initializations bzw. Proxy-Objekte, die von Hibernate davor geschlanzt werden...
 
SnooP hat gesagt.:
Problem sind da die Lazy-Initializations bzw. Proxy-Objekte, die von Hibernate davor geschlanzt werden...

Abhilfe?

Hab schon rausgefunden, dass ich auf jene Objekte nur bei einer offenen/gültigen Session zugreifen kann.

Also folgendes funktioniert (siehe sysout:
Code:
public static List<FeatureInterconnectionModel> findEntries(final Integer fromId, final Integer toId) {
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = null;		
		List<FeatureInterconnectionModel> list = null;		
		try {
			tx = session.beginTransaction();	
			Query q = session.createQuery(
					"from FeatureInterconnectionModel t where t.featureFrom = :fromId and t.featureTo = :toId");
			q.setInteger("fromId", fromId);
			q.setInteger("toId", toId);
			System.out.println(q.getQueryString());
			list = q.list();
			
			System.out.println(list.get(0).getFeatureId().getId());
			System.out.println(list.get(0).getFeatureId().getName());
			
			/* commit and close session */
			tx.commit();	
		} catch (Exception e) {
			if (tx != null) {
				tx.rollback();
				e.printStackTrace();
			}
		} finally {
			session = null;
			tx = null;
		}
		return list;
	}

Folgendes funktioniert nicht:
Code:
		Integer fromId = 2247430;
		Integer toId = 2247431;
		List<FeatureInterconnectionModel> dd = FeatureInterconnectionDB.findEntries(fromId, toId);
		System.out.println(dd.get(0).getFeatureId().getId()); // das hier funktioniert, also Zugriff auf ID
		System.out.println(dd.get(0).getFeatureId().getFeatureTypeId()); //das hier geht schon nicht mehr u wirft die Ausnahme
 
ha 😉 ... noch vor dem Edit... - wenn die Session geschlossen wurde, bevor 1:x Beziehungen geladen wurden, kommst du da nicht mehr dran...

Lösungsmöglichkeiten gibt's da natürlich viele...

a) du lässt so lange die Session auf, bis du die Daten brauchst... - bringt aber auch Probleme mit sich 😉

b) du stellst die Beziehung auf fetch = FetchType.Eager - dadurch bekommst du das Objekt aber immer mit... d.h. zwangsweise join/subselect

c) du holst dir das Objekt via HQL, SQL oder Criteria-Abfrage - dann kannst du dir auch explizit immer das Feature-Objekt ziehen... hat den Vorteil gegenüber b), dass nur in den Fällen das Objekt geholt werden muss, in denen du es auch brauchst...

Wenn du das aber eh immer brauchst, wäre eager gar nicht mal schlecht...
 
zu a:
Jo das ist keine alternative 🙂

zu b:
wo trage ich dieses fetch ein, sprich in welchem hbm? und was meinst du mit zwangsweise join/subselect - muss ich hier dann einen join selber machen?

zu c:
ich hole mir mit dem stmt ja schon das objekt per hql? oder meinst du ich mache 2 stmts?


**EDIT**
zu b:
Also ich habe nun testweise fetch=join mit beiden hbm files probiert - ist es egal in welches ich es hineinschreibe oder muss es sogar in beiden stehen? worin besteht hier eigentlich der nachteil? c wäre wohl die bessere alternative (nur verstehe ich nicht was du bei c meinst).
 
zu b:

Code:
<class name="at.pcd.wam.technologie.persistence.model.FeatureInterconnectionModel"
      table="FEATURE_INTERCONNECTION" lazy="false">
 
maki hat gesagt.:
zu b:

Code:
<class name="at.pcd.wam.technologie.persistence.model.FeatureInterconnectionModel"
      table="FEATURE_INTERCONNECTION" lazy="false">

Also schreibe ich das nicht genau zur Beziehung sondern in den hbm kopf - worin besteht der nachteil?
Es funktioniert aber auch wenn ich das lazy=false in das andere hbm file schreibe.
wäre c die elegantere lösung u wie sehe jene bspw aus?
 
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
at at.pcd.wam.technologie.persistence.model.FeatureModel$$EnhancerByCGLIB$$294ecce8.getName(<generated>)
Dein Featuremodel ist gar kein Featuremodel Objekt, sondern ein von Hibernate erzeugter Proxy.
Der Nachteil es in den kopf eintzutragen ist, dass immer ganze Objekte gelesen werden, selbst wenn es sich nur zB um eine Liste handelt.

Hier ein Pattern von den Hibernate Jungs selbst:
http://www.hibernate.org/43.html
 
Kann sein, dass c so zu verstehen war (scheint mir die einfachste Lösung):
Code:
	public static List<FeatureModel> findEntries(final Integer fromId, final Integer toId) {
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = null;		
		List<FeatureInterconnectionModel> list = null;	
		List<FeatureModel> list2 = new LinkedList<FeatureModel>();
		try {
			tx = session.beginTransaction();	
			Query q = session.createQuery(
					"from FeatureInterconnectionModel t where t.featureFrom = :fromId and t.featureTo = :toId");
			q.setInteger("fromId", fromId);
			q.setInteger("toId", toId);
			list = q.list();

			for (FeatureInterconnectionModel model : list) {
				list2.add(model.getfModel());
			}
			System.out.println(list.get(0).getfModel().getId());
			System.out.println(list.get(0).getfModel().getName());
			
			/* commit and close session */
			tx.commit();	
		} catch (Exception e) {
			if (tx != null) {
				tx.rollback();
				e.printStackTrace();
			}
		} finally {
			session = null;
			tx = null;
		}
		return list2;
	}
 
Was war das eigentliche Problem nochmal?
Du hast doch die Session laufend offen, da kann es doch ruhig lazy sein, oder hab ich was übersehen?

ms
*verschlafen*
 
In seiner main wertet er die list2 aus, da ist die Session schon geschlossen 😉
 
Also hab ich c nun so umgesetzt wie es gemeint war? möchte nicht unbedingt lazy auf false setzen, da ich lazy auf true bei einer anderen sache eventuell noch benötige.
 
ne das ist egal... - den fetch-type kannst du direkt an die attribute schreiben... ansonsten werden halt alle attribute automatisch nicht-lazy gefetched...

c wäre nur dann elegant, wenn du auch andere Fälle hast, wo du das Objekt evtl. nicht brauchst... - typisches Beispiel wären Personen mit Adressen. In den meisten Fällen brauchst du die Adressen nicht - dann gibt es aber auch Dialoge wo sowohl Personen als auch die Adressen mit angezeigt werden... - bei letzterem wäre also eager sinnvoll, sonst nicht. Klassisches Dilemma 😉 ... wenn du aber eh in 90% der Fälle auch die Adresse brauchst, dann zieh sie via eager-fetching immer mit.

eigentlich hab ich mal gelernt, dass wenn man HQL verwendet - man also nen query macht, automatisch die Teile eager geladen werden. Aber hab grad nochmal geguckt... war im Irrtum - du musst beim hql explizit das fetch mit angeben... da du aber theta-style gemacht hast, weiß ich grad nich wie... - mal überlegen 😉

from FeatureInterconnectionModel t left join fetch t.features where t.featureFrom = :fromId and t.featureTo = :toId

so ungefähr?
 
SnooP hat gesagt.:
ne das ist egal... - den fetch-type kannst du direkt an die attribute schreiben... ansonsten werden halt alle attribute automatisch nicht-lazy gefetched...

c wäre nur dann elegant, wenn du auch andere Fälle hast, wo du das Objekt evtl. nicht brauchst... - typisches Beispiel wären Personen mit Adressen. In den meisten Fällen brauchst du die Adressen nicht - dann gibt es aber auch Dialoge wo sowohl Personen als auch die Adressen mit angezeigt werden... - bei letzterem wäre also eager sinnvoll, sonst nicht. Klassisches Dilemma 😉 ... wenn du aber eh in 90% der Fälle auch die Adresse brauchst, dann zieh sie via eager-fetching immer mit.

eigentlich hab ich mal gelernt, dass wenn man HQL verwendet - man also nen query macht, automatisch die Teile eager geladen werden. Aber hab grad nochmal geguckt... war im Irrtum - du musst beim hql explizit das fetch mit angeben... da du aber theta-style gemacht hast, weiß ich grad nich wie... - mal überlegen 😉

from FeatureInterconnectionModel t left join fetch t.features where t.featureFrom = :fromId and t.featureTo = :toId

so ungefähr?

Also wie nun? Maki meinte ich muss im hbm kopf fetch = false eintragen damit b umgesetzt wird, du meinst nun ich muss im hql stmt einen JOIN machen - bissl verwirrt bin ich nun.


**EDIT**
ok hab es nun so umgesetzt sie SnooP meinte und es funktioniert auch, nur verstehen tue ich nicht, was hier passiert. durch das FETCH wird das feature gleich geladen und nicht als Proxy?
Code:
@SuppressWarnings("unchecked")
	public static List<FeatureInterconnectionModel> findFeatures(final Integer fromId, final Integer toId) {
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = null;		
		List<FeatureInterconnectionModel> list = null;	
		List<FeatureModel> retList = new LinkedList<FeatureModel>();
		try {
			tx = session.beginTransaction();	
			Query q = session.createQuery("from FeatureInterconnectionModel t left join fetch t.fModel"
					+ "where t.featureFrom = :fromId and t.featureTo = :toId");
			q.setInteger("fromId", fromId);
			q.setInteger("toId", toId);
			list = q.list();
			/* commit and close session */
			tx.commit();	
		} catch (Exception e) {
			if (tx != null) {
				tx.rollback();
				e.printStackTrace();
			}
		} finally {
			list = null;
			session = null;
			tx = null;
		}
		return list;
	}
 
ja so wie du's gemacht hast gehts übrigens auch 😉

[edit]
immer dieses chatten im forum 😉 ...

alsooo - entweder du stellst lazy=eager bzw. false (dasselbe) im mapping ein... dann ist es immer eager, was man ja evtl. aber nicht will (wie du schon gesagt hast). Oder man greift während die session offen ist auf das zunächst lazy geladene Objekt zu und holt es dadurch explizit rein (wenn du in der hibernate-config <property name="show_sql">true</property> stellst kannst du auch sehen, dass dann erst ein nächstes sql kommt). Oder du holst dir beim direkten zugriff via query das layz eingestellte objekt durch den fetch join explizit, d.h. du stellst im query ein, dass du das auf jeden Fall brauchst und auf lazy verzichten kannst für diesen Fall. Halte ich persönlich für am besten 😉

[/edit]
 
Also wie nun? Maki meinte ich muss im hbm kopf fetch = false eintragen damit b umgesetzt wird, du meinst nun ich muss im hql stmt einen JOIN machen - bissl verwirrt bin ich nun.
Nee, maki meinte:

Hibernate Doku lesen schadet auch nicht, besser gleich das Buch.
Ist ne steile lernkurve, aber lohnt sich 😉
 
Hab hier ein Buch rumliegen "Hibernate Persistenz in Java-Systemen mit Hibernate und der Java Persistence API" von dpunkt.verlag
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben