M-zu-N-Beziehungen und JPA

vorhergehende Artikel in: Komponenten sQLshell Datenbanken
05.04.2022

Ich habe bereits darüber berichtet, dass die sQLshell ein neues Plugin anbietet, das aus bestehenden Datenmodellen in Datenbanken JPA-Entityklassen generieren kann.

Neulich bin ich bei meinen Tests über eine Eigenart gestolpert, die mich einige Stunden des Suchens gekostet hat, bis ich die Ursache dafür fand:

Ich experimentierte mit M-zu-N-Beziehungen (in JPA mittels @ManyToMany Annotationen modelliert) in meinem auf GitHub veröffentlichten Projekt für Tests für dieses neue Plugin.

Konkret wollte ich bei drei Klasen A, B und M bei denen A und B über eine Mapping-Tabelle M mittels einer solchen M-zu-N-Beziehung verknüpft waren neue Entities hinzufügen und diese neuen Entities in den Tabellen A und B entsprechend verknüpfen.

Das funktioniert mit einer explizit als Entity mopdellierten Mappingtabelle M zum einen über das Persistieren entsprechender Entities in M. Zum anderen müsste es eigentlich möglich sein, ein Entity zum Beispiel für A zu persistieren, anschließend eines für B zu erzeugen, dessen Getter für die verknüpften Entities in A aufzurufen und diesem Ergebnis (einer Collection) dann das neu erzeugte A-Entity hinzufügen und dieses anschließend ebenfalls zu persistieren. Dadurch sollte automatisch eine entsprechende Zeile in der Mappingtabelle M auftauchen.

Genau das funktionierte jedoch nicht. An dieser Stelle noch einige Hintergrundinformationen: A, B und M hatten jeweils ein mittels @Id annotiertes Feld, das letztlich der Primärschlüsselspalte in der Tabelle entsprach. Jedes dieser Felder war darüber hinaus mit einer Annotation @GeneratedValue und der strategy GenerationType.AUTO versehen, die dafür sorgt, dass man beim Erzeugen von Entities aus der Anwendung heraus keine Primärschlüssel manuell festlegen muss. Das funktionierte hervorragend für das explizite Anlegen von Entities jeweils in den Tabellen A, B und M.

Wenn ich jedoch die oben skizzierte Variante für das Anlegen einer Relation versuchte, bei der die Entity bzw. die neue Zeile in M implizit erzeugt werden sollte, wurde jeder dieser Versuche mit einem Fehler quittiert, der letztlich aussagte, dass es nicht erlaubt sei, in die Primärschlüsselspalte von M eine NULL einzutragen.

Nach schier endloser Sucherei und immer verzweifelterem Herumprobieren fand ich schließlich die Lösung: Ich hatte glücklicherweise ein zweites Datenmodell zur Hand, in dem ebenfalls eine M-zu-N-Beziehung bestand. In diesem Datenmodell funktionierte die implizite Erzeugung des Entities der Mappingtabelle wie gewünscht. Nachdem ich mir sicher war, dass die Entityklassen bis auf die Namen identisch annotiert waren, untersuchte ich die Datenbanken. In beiden Fällen handelte es sich um Postgres mit der identischen Version 42.2.18 des JDBC-Treibers.

Allerdings entdeckte ich einen Unterschied im Datenmodell: Dort, wo die implizite Erzeugung des Entity funktionierte war die Primärschlüsselspalte vom Typ SERIAL, während sie dort, wo es nicht funktionierte vom Typ INTEGER war. Nachdem ich diesen Fakt anglich, funktionierte plötzlich auch dort alles, wo es sich vorher standhaft geweigert hatte.

Die Erkenntnis also: Arbeitet man mit JPA bzw. der Implementierung hibernate core in der Version 5.4.23.Final, so sollte man darauf achten, dass die Primärschlüsselspalten in Mapping-Tabellen für M-zu-N-Beziehungen immer vom Typ SERIAL sind.

Das brachte mich dazu, die Versionen schleunigst anzupassen - immerhin stammten die benutzten noch aus dem Jahr 2020. Also änderte ich die Abhängigkeite wie folgt: Ich nutzte den Postgres-Treiber in Version 42.3.3 und Hibernate in Version 5.6.7.Final.

Jedoch blieb auch in den neueren Versionen das Problem exakt so bestehen.

Alle Artikel rss Wochenübersicht Monatsübersicht Github Repositories Gitlab Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • Fährnisse des Buildprozesses unter Windows

    17.07.2019

    Nachdem ich begonnen hatte, mich mit der Beschleunigung der Berechnung des Mandelbrot-Fraktals unter Zuhilfenahme der Shadereinheiten in Graphikkarten zu beschäftigen und erste Erfolge feiern konnte, wollte ich das mal auf einer richtigen Graphikkarte ausprobieren...

    Weiterlesen...

Neueste Artikel

  • Datenvalidierung UTF8 mit BiDi-Steuerzeichen (TrojanSource 2.0)

    Ich bin heute nochmal inspiriert worden, weiter über die Trojan Source Vulnerability nachzudenken. Meiner Meinung nach bestehen hier noch Probleme - speziell bei Nutzereingaben oder Daten, die über externe Schnittstellen ampfangen werden.

    Weiterlesen...
  • OpenStreetMap Navi als Docker-Container

    Ich habe die auf OpenStreetMap basierende OpenSource Navigationslösung Graphhopper in einen Docker-Container gepackt und als neuestes Mitglied in meinem Docker-Zoo willkommen geheißen.

    Weiterlesen...
  • SQL-Aggregatfunktionen in SQLite als BeanShell-Scripts

    Ich habe neulich über eine Möglichkeit berichtet, SQLite mittels der sQLshell und Beanshell-Skripten um SQL-Funktionen zu erweitern. In diesem Artikel versprach ich auch, über eine solche Möglichkeit für Aggregatfunktionen zu berichten.

    Weiterlesen...

Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.

Wer daran teilhaben und eventuell sogar davon profitieren möchte, muß damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.

Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...

PS: Meine öffentlichen GitHub-Repositories findet man hier - meine öffentlichen GitLab-Repositories finden sich dagegen hier.