# hibernate und ManyToOne



## Gast2 (2. Jan 2010)

Hallo,

ich hab 2 Klassen mit einer undirektionalen ManyToOne bez.
So jetzt will ich erreichen, dass wenn ich A lösche dass dann auch alle dazugehörigen b's gelöscht werden, wie bekomme ich das hin?

klasse b

```
@ManyToOne
	@JoinColumn(name="a_fk")
	@Override
	public A getA() {
		return a;
	}
	@Override
	public void setA(A a) {
	this.a= a;
	}
```


danke


----------



## fastjack (3. Jan 2010)

Das läuft bei Hibernate mit "Cascade Annotations", einfach mal googlen.


----------



## Gast2 (3. Jan 2010)

Hab ich versucht

```
org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
	at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:634)
	at org.springframework.orm.hibernate3.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:793)
	at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:664)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:767)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:736)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:394)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
	at $Proxy25.deleteMitarbeiterByID(Unknown Source)
	at ui.editor.MitarbeiterEditor.delete(MitarbeiterEditor.java:330)
	at ui.command.DeleteHandler.execute(DeleteHandler.java:21)
	at org.eclipse.ui.internal.handlers.HandlerProxy.execute(HandlerProxy.java:294)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:476)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:508)
	at org.eclipse.ui.internal.handlers.HandlerService.executeCommand(HandlerService.java:169)
	at org.eclipse.ui.internal.handlers.SlaveHandlerService.executeCommand(SlaveHandlerService.java:241)
	at org.eclipse.ui.menus.CommandContributionItem.handleWidgetSelection(CommandContributionItem.java:770)
	at org.eclipse.ui.menus.CommandContributionItem.access$10(CommandContributionItem.java:756)
	at org.eclipse.ui.menus.CommandContributionItem$5.handleEvent(CommandContributionItem.java:746)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1003)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3880)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3473)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2405)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2369)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at rcptest.Application.start(Application.java:20)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1287)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:172)
	at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
	at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
	at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
	at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
	at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
	... 42 more
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`verwaltung`.`termin`, CONSTRAINT `FK951BD2B13A9AD6A4` FOREIGN KEY (`mitarbeiter_fk`) REFERENCES `mitarbeiter` (`id`))
	at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2007)
	at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1443)
	at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)
	at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)
	at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
	... 50 more
```


```
@ManyToOne(cascade=CascadeType.REMOVE)
	@JoinColumn(name="mitarbeiter_fk")
	@Override
	public Mitarbeiter getMitarbeiter() {
		return mitarbeiter;
	}
```

CascadeType.ALL bringt auch nichts??????:L

EDIT: dass passiert natürlich nur wenn der fk in der anderen klasse ist , also wenn es eine beziehung gibt...


----------



## Gast2 (8. Jan 2010)

Hat keiner eine Idee?


----------



## Gast2 (12. Jan 2010)

Irgendwie habe ich das gefühl, dass das gar nicht geht!!!
Ich glaube ich muss auf der A seite die Beziehung machen und ein delete orphan machen...
Leider ist die Beziehung dann nicht mehr undirektional...


----------



## velaluka (12. Jan 2010)

Hallo SirWayne,
bin neulich auf das gleiche Problem gestossen und musste feststellen das sowas garnicht möglich ist. Ich war einwenig erschüttert aber es scheint fackt zu sein. Wenn man anfängt zu googlen, findet man z.B ne Hack der direkt die H Source ändert(besser gehts nimmer). Zum Glück konnte ich meine Beziehung auch von der anderen Seite aufziehen allerdings finde ich das wirklich armselig von Hibernate. Sogar OJB konnte schon ein delete cascade........

Ciao velaluka


----------



## velaluka (12. Jan 2010)

Wer lesen kann ist klar im Vorteil ich meinte OneToMany
ManyToOne probiers mal so:

```
@OnDelete(action = org.hibernate.annotations.OnDeleteAction.CASCADE)
```
Ciao velaluka


----------



## Gast2 (12. Jan 2010)

velaluka hat gesagt.:


> Wer lesen kann ist klar im Vorteil ich meinte OneToMany
> ManyToOne probiers mal so:
> 
> ```
> ...



Danke muss ich daheim mal testen!


----------



## byte (12. Jan 2010)

SirWayne hat gesagt.:


> ich hab 2 Klassen mit einer undirektionalen ManyToOne bez.
> So jetzt will ich erreichen, dass wenn ich A lösche dass dann auch alle dazugehörigen b's gelöscht werden, wie bekomme ich das hin?
> 
> klasse b
> ...



Was Du vorhast, kann doch IMHO gar nicht funktionieren. A hat keine Referenz auf B. Woher soll Hibernate also wissen, welche Bs er löschen soll, wenn Du ein A löscht? Mit Cascade.DELETE kommst Du hier IMHO auch nicht weiter, da Du ja ManyToOne benutzt: "viele Bs können genau ein A haben". Löscht Du also ein B und kaskadierst das löschen zum A, dann wird die referenzielle Integrität bei anderen Bs, die auf das A zeigen, möglicherweise verletzt.

Du könntest nun entweder eine bidirektionale Verbindung draus machen. Oder Du implementierst die Löschen-Methode anders, so dass Du erst alle Bs mit Referenz auf A löscht und dann erst A selbst.


----------



## Gast2 (12. Jan 2010)

byte hat gesagt.:


> Was Du vorhast, kann doch IMHO gar nicht funktionieren. A hat keine Referenz auf B. Woher soll Hibernate also wissen, welche Bs er löschen soll, wenn Du ein A löscht? Mit Cascade.DELETE kommst Du hier IMHO auch nicht weiter, da Du ja ManyToOne benutzt: "viele Bs können genau ein A haben". Löscht Du also ein B und kaskadierst das löschen zum A, dann wird die referenzielle Integrität bei anderen Bs, die auf das A zeigen, möglicherweise verletzt.


Ja hab ich mir auch schon gedacht, dachte es gäbe eventuell eine andere Möglichkeit als eine Beziehung... Aber okay gut zu wissen =)!!!




byte hat gesagt.:


> Du könntest nun entweder eine bidirektionale Verbindung draus machen. Oder Du implementierst die Löschen-Methode anders, so dass Du erst alle Bs mit Referenz auf A löscht und dann erst A selbst.


Ja das mit der bidirektionale Verbindung muss ich mal schauen, ob das gescheit geht! Aber ein versuch ist es wert... Reicht dann der Cascade typ delete oder brauch ich delete_orphan 
2ter Vorschlag ist grad so im Einsatz...


----------



## Gast2 (12. Jan 2010)

So habs jetzt mal bidirketion veruscht

```
@OneToMany(cascade = CascadeType.ALL, mappedBy = "a")
	@Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	public Set<B> getB() {
		return bs;
	}
```

und


```
@ManyToOne
	@Override
	public A getA() {
		return a;
	}
```


```
aused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails
```


----------



## KSG9|sebastian (25. Jan 2010)

Ein Cascade-Delete auf eine ManyToOne macht keinen Sinn, dabei kommt es natürlich oft zu entsprechenden ConstraintViolations.
Poste mal ein bisschen mehr Code:

- wie wird gelöscht (Code dazu..session.remove(??))
- poste mal die SQLs die abgesetzt werden

So wie das aussieht löscht Hibernate in der falschen Reihenfolge.
Mach mal nen ophan-delete für die Collection, dann ein Collection.clear() und dann saveOrUpdate.

Der bessere Weg sowas zu bauen ist wohl zuerst alle Children zu "dereferenzieren", dann löschen und danach das Parent löschen.

ManyToOne mit cascade-delete finde ich etwas abstrus


----------

