22.11.2012

Criteria API - CAST ( .. AS .. )

Wer kennt es nicht? Der ewige Zwist zwischen (alt-eingessenen) DBAs und dem Programmierer an sich. Im wesentlichen zwei Spezies, die meist nur schwer miteinander zu vereinen sind.

Ich muss zugeben, dass das nicht immer stimmt, denn die Mehrzahl der Gespräche sind im wesentlichen sinnvoll. Die Probleme bestehen meist eher in dem antiquierten Datenbankmodell, was über die Jahre gewachsen und gewachsen und gewachsen ist. Da schleicht sich meist die eine oder andere Inkonsistenz ein, gerade was die Typen innerhalb einer Tabelle angeht. Da werden Zahlwerte als char-Felder mit festen Längen gespeichert, Datumsangaben mal als Timestamp, dann wieder als char und zwischendurch auch mal ganz anders.

Trifft man auf solche Probleme, sind immer spezielle Lösungen erforderlich um die eigentlichen Anforderungen umzusetzen. Am einfachsten wird das Problem anhand eines Beispiels klar. Die gegebene Tabellenstruktur ist gekennzeichnet durch das folgende SQL:



Dort ist klar zu erkennen, dass die Spalte INT_VALUE in der Datenbank als varchar(5) abgebildet wird. Die Entität selbst bildet die Spalte allerdings auf einen int-Wert ab.


Beim Mapping durch Hibernate werden noch keinerlei Probleme sichbar. Das Mapping kann ohne weitere Probleme durchgeführt werden und ein erster Test ist erfolgreich.



Auch das Auslesen ist für korrekt eingefügte Werte möglich.


Das dies funktioniert liegt allein daran, dass Hibernate bereits einen Teil der Konvertierung übernimmt und die in der Datenbank befindlichen Werte automatisch in die passenden Werte überführt. Deutlich wird dies, wenn einer der Werte nicht mehr numerisch, sondern alphanumerisch ist.


Sofort tritt eine DataException auf, die den Test fehlschlagen lässt, da der geänderte Wert "10A" nicht konvertiert werden kann.

Nun stellt sich die Frage, für welchen Fall ein CAST überhaupt benötigt wird. Die Konvertierung geschieht augenscheinlich automatisch und lieferte korrekte Ergebnisse, wenn die Daten konsistent sind und das Mapping den korrekten Datentypen besitzt. Was passiert aber, wenn die Entität nicht den fachlich korrekten Typen besitzt, sondern an die Deklaration in der Datenbank angelehnt ist?


Damit wird bereits ein einfacher Test zum Problem. Werden alle Produkte mit einem Wert zwischen 1 und 5 abgefragt, sollten 5 Produkte zurückgegeben werden.


Der Test schlägt fehl. Es werden nicht nur die Produkte mit einem Wert zwischen 1 und 5 zurückgegeben, sondern auch das Produkt mit dem Wert 10, da dieses bei einem einfachen Vergleich ebenfalls als korrektes Ergebnis erkannt wird. Das ist in diesem Fall aber gar nicht gewünscht.

Somit muss eine Alternative gefunden werden. Ein möglicher Lösungsansatz ist das Einfügen einer nativen Bedingung mit einem nativen Cast der Werte. Dafür bietet die Criteria-API die Möglichkeit eine Restriktion mit nativem SQL zu definieren.


Mit Hilfe der nativen Einschränkung kann das Statement so erweitert werden, dass ein Vergleich direkt auf numerischer Basis in der Datenbank durchgeführt wird, {alias} sorgt hier für die Angabe der richtigen Tabelle. Anschließend müssen nur noch die Parameter inkl. der zugehörigen Typen gesetzt werden und die Datenbank übernimmt die eigentliche Arbeit. Der Test ist grün.


Sicherlich wäre der elegantere Weg, dass die Entität fachlich korrekt definiert wird und eine automatische Umwandlung durch Hibernate stattfindet. Allerdings ist dies in vielen Fällen nicht möglich, da das Objektmodell nicht angepasst werden soll.

Das Beispiel findet sich wie immer im Repository.




Kommentare:

  1. Danke Marcin.

    Ich habe es versäumt zu verlinken, das hole ich entsprechend nach!

    Sorry!

    AntwortenLöschen