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


Neueste Artikel

  • Github hat keine Ahnung von Crypto und Sicherheit

    Morgen - am 1.2.2023 - soll mein neuer $dayjob anfgangen - und damit die Quelle, aus der ich die Mittel beziehe, weiterhin meine Kuchenzutaten bezahlen zu können. Das wird irgendwas mit Sicherheit sein. Und am Tag davor hat sich - wer eigentlich genau? - überlegt: "Komm, lass ihn uns nochmal so richtig auf Betriebstemperatur überkochen!". Aber - der Reihe nach...

    Weiterlesen...
  • Aktualisierung TileServer - Restrukturierung

    Ich habe meinen Tile-Server für OpenStreetMap-Daten aktualisiert

    Weiterlesen...
  • Drunken Bishop in Java

    Ich habe neulich wieder einmal Lust auf eine kleine Fingerübung gehabt und deshalb ein Verfahren in Java implementiert, das ich ursprünglich als Möglichkeit kennenlernte, zwei Schlüssel beim Versuch des Aufbaus einer Verbindung mittels SSH zu vergleichen...

    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.