# Hibernate - 1:1 Beziehung liefert leeres Objekt



## y0dA (6. Dez 2007)

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:

```
<?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:

```
<?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:

```
from FeatureModel t where t.id = 3277
```

Folgendes liefert mir leider ein Objekt mit null Einträgen:

```
from FeatureInterconnectionModel t where t.featureFrom = :fromId and t.featureTo = :toId
```


----------



## y0dA (6. Dez 2007)

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:

```
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:

```
from FeatureInterconnectionModel t where t.featureFrom = :fromId and t.featureTo = :toId 
[code]

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

jener Objektzugriff funktioniert:

```
fInterconnectionModel.getFeatureId().getId());
```


----------



## SnooP (6. Dez 2007)

Problem sind da die Lazy-Initializations bzw. Proxy-Objekte, die von Hibernate davor geschlanzt werden...


----------



## y0dA (6. Dez 2007)

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:

```
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:

```
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
```


----------



## SnooP (6. Dez 2007)

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...


----------



## y0dA (6. Dez 2007)

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).


----------



## maki (6. Dez 2007)

zu b:


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


----------



## y0dA (6. Dez 2007)

maki hat gesagt.:
			
		

> zu b:
> 
> 
> ```
> ...



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?


----------



## maki (6. Dez 2007)

> 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


----------



## y0dA (6. Dez 2007)

Kann sein, dass *c* so zu verstehen war (scheint mir die einfachste Lösung):

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


----------



## ms (6. Dez 2007)

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*


----------



## maki (6. Dez 2007)

In seiner main wertet er die list2 aus, da ist die Session schon geschlossen


----------



## y0dA (6. Dez 2007)

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.


----------



## SnooP (6. Dez 2007)

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?


----------



## y0dA (6. Dez 2007)

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.
> 
> ...



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?

```
@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;
	}
```


----------



## SnooP (6. Dez 2007)

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]


----------



## y0dA (6. Dez 2007)

Ok danke - wieder einiges gelernt.

dank euch.


----------



## maki (6. Dez 2007)

> 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:


> lazy="false"



Hibernate Doku lesen schadet auch nicht, besser gleich das Buch.
Ist ne steile lernkurve, aber lohnt sich


----------



## y0dA (6. Dez 2007)

Hab hier ein Buch rumliegen "Hibernate Persistenz in Java-Systemen mit Hibernate und der Java Persistence API" von dpunkt.verlag


----------



## maki (6. Dez 2007)

Kenn ich nicht, ich das hier gut: 
http://www.amazon.com/Java-Persistence-Hibernate-Christian-Bauer/dp/1932394885


----------

