# HibernateMapping



## dcasdererwe (14. Aug 2012)

Hallo,
ich habe folgende Datenbankstruktur. Für jedes Gerät gibt es eine Tabelle in der die zugehörigen Messwerte geloggt werden:

Tabelle "GeräteID1"
---> Messwert 1, Datum 1, .....
---> Messwert 2, Datum2, ......


Tabelle "GeräteID2"
---> Messwert 1, Datum 1, .....
---> Messwert 2, Datum2, ......


Ich habe mir jetzt über reverse engineering das mappingfile und das POJO von der Tabelle "GeräteID1" erzeugt und kann nun Messwerte für Gerät 1 lesen und schreiben.
Wie kann ich das mappingfile / pojo verändern, um mit folgendem Aufruf Messwerte zu speichern?

```
session.save(new Messwert ("GeräteID", "Messwert1234", new Date(), ........));
 tx.commit();
```
Hibernate soll die Werte automatisch in die richtige Tabelle schreiben, falls Tabelle nicht vorhanden, soll sie nach dem Muster von "GeräteID1" erzeugt werden.



Einen zweiten Fehler habe ich noch bei der Anbindung an Postgres 9.1. Hibernate vergisst die Anführungszeichen um die Spaltennamen.
Meine hibernate.cfg.xml für Postgres:

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
        <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
        <property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/tabellenname</property>
        <property name="hibernate.connection.username">xxxxxxx</property>
        <property name="hibernate.connection.password">xxxxxxx</property>
         <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>
        <property name="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</property>
        <property name="show_sql">true</property>
        <mapping resource="javaapplication1/Log.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
```

Das erzeugte SQL-Statement:

```
insert into public.log (Messwert, Datum, ........)  values (?,?,.......)
```

Durch die fehlenden "" kommt es zur Fehlerausgabe:

```
Schwerwiegend: FEHLER: Spalte »messwert« von Relation »log« existiert nicht
```


VIELEN DANK FÜR EURE HILFE


----------



## nillehammer (14. Aug 2012)

So wie Du es Dir vorstellst, anhand der übergebenen Geräte-ID quasi dynamisch die richtige Tabelle zu finden, wird von Hibernate nicht unterstützt. Aus dem Dilemma siehe ich drei mögliche Auswege:

Du schreibst Dir eine DAO-Methode, die das entsprechend flexibel handhabt
Du schreibst eine abstrakte Klasse Geraet (MappedSuberclass) und leitest von dieser Klasse Geraet1, Geraet2 etc ab. Die abgeleiteten Klassen (Entity) kannst du dann 1 zu 1 auf die DB-Tabelle mappen.
Du machst Dir Gedanken über Dein Datenmodell. Es scheint mir keine gute Idee, für jedes Gerät eine extra Tabelle zu nehmen. Ich würde eher *eine* Tabelle Geraet sehen, die die Daten *aller* Geräte aufnimmt. Und dann eine Tabelle Messwert. Diese nimmt alle Messwerte auf und hat einen Fremdschlüssel zu Geraet. Dann kannst Du über OneToMany/ManyToOne so mappen, wie es dich gehört.


----------



## dcasdererwe (14. Aug 2012)

nillehammer hat gesagt.:


> Es scheint mir keine gute Idee, für jedes Gerät eine extra Tabelle zu nehmen. Ich würde eher *eine* Tabelle Geraet sehen, die die Daten aller Geräte aufnimmt. Und dann eine Tabelle Messwert. Diese nimmt alle Messwerte auf und hat einen Fremdschlüssel zu Geraet. Dann kannst Du über OneToMany/ManyToOne so mappen, wie es dich gehört.



Vielen Dank für die schnelle Antwort. Die Struktur ist "historisch gewachsen". Ich persönlich würde auch nur eine Tabelle "Gerät" machen, aber wird nicht gewünscht


----------



## dcasdererwe (14. Aug 2012)

Eventuell hat es auch den Grund, dass die Abfragen durch das Vorselektieren schneller laufen. In einer Gerätetabelle liegen nicht nur 3 Messwerte ;-)


----------



## nillehammer (14. Aug 2012)

dcasdererwe hat gesagt.:
			
		

> Die Struktur ist "historisch gewachsen". Ich persönlich würde auch nur eine Tabelle "Gerät" machen, aber wird nicht gewünscht


Hab ich mir gedacht, deswegen hatte ich noch zwei andere Alternativen hingeschrieben. Ich würde dann an Deiner Stelle die zweite umsetzen.


----------



## nillehammer (14. Aug 2012)

> Eventuell hat es auch den Grund, dass die Abfragen durch das Vorselektieren schneller laufen. In einer Gerätetabelle liegen nicht nur 3 Messwerte


Das bezweifle ich. Eine Abfrage mit einem *einzigen* INNER JOIN auf die GeräteId wird vom DBMS schnell genug abgearbeitet. Dies ist kein Grund für eine De-Normalisierung.


----------



## dcasdererwe (14. Aug 2012)

nillehammer hat gesagt.:


> Das bezweifle ich. Eine Abfrage mit einem *einzigen* INNER JOIN auf die GeräteId wird vom DBMS schnell genug abgearbeitet. Dies ist kein Grund für eine De-Normalisierung.


Das werde ich morgen mal mit ein paar Abfragen testen, wie sich das auf die Laufzeit auswirkt. Wenn sie nicht signifikant ansteigt, werde ich alles in eine Tabelle schreiben. 


Ich hänge immernoch an dem Postgres-Problem fest (mit den anderen DB-Typen funktioniert es).

```
select messwert from geraetID1
```
schlägt fehl mit 

```
********** Fehler **********

FEHLER: Spalte »messwert« existiert nicht
SQL Status:42703
Zeichen:8
```

Es funktioniert nur über

```
select "Messwert" from geraetID1
```
aber Hibernate formatiert die Abfrage falsch. Hab mich jetzt durch diverse Foren gelesen, aber keine zielführende Antwort in bezug auf Hibernate gefunden.


----------



## nillehammer (14. Aug 2012)

> select "Messwert" from geraetID1


Dass man bei Queries die Namen der anzuzeigenden Spalten in Hochkommas setzen *muss*, hab ich noch nie gehört. Ich glaube nicht, dass das nötig ist. Was aber sein kann ist, dass Postgres die Spaltennamen case-sensitive auswertet, sprich, dass Groß-/Klein-Schreibung zu beachten ist. Da hilft Dir ein @Column(name="Messwert") über dem getter oder der Instanzvariablen.


----------



## dcasdererwe (14. Aug 2012)

Vielen vielen Dank! *case-sensitive* war genau das Stichwort was mir gefehlt hat!
Keine Lust da mit Anotations rumzuwerkeln. Habe einfach ne neue DB angelegt, die hbm.xml um die Spalte "DeviceID" erweitert und Hibernate die Tabelle "Messwerte" erzeugen lassen.
Habe grad mal hochgerechnet, wird interessant mit der Laufzeit wenn man mal nen Select absetzt, da es ein paar mrd Datensätze werden.


----------



## Nogothrim (14. Aug 2012)

eigentlich schreibt postgres gerne alles klein und ist eher nicht case-sensitive bei Spalten und Tabellennamen, vielleicht irgendwas am db server komisch eingestellt? Habe allerdings keine Ahnung was diese ClassicQueryTranslatorFactory macht, vielleicht verbiegt die irgendwas. Ich kenne Hibernate nur über JPA.


----------



## dcasdererwe (15. Aug 2012)

nillehammer hat gesagt.:


> Das bezweifle ich. Eine Abfrage mit einem *einzigen* INNER JOIN auf die GeräteId wird vom DBMS schnell genug abgearbeitet. Dies ist kein Grund für eine De-Normalisierung.


Bei mio. oder gar mrd. Datensätzen dauert das aber ne Weile.
Extremfall:
100 Geräte. 100mio Datensätze. Gerät 5 hat nur 100 Datensätze.
Ich möchte die Werte in Spalte xy von Gerät 5 aufsummieren. 

Habe gerade "nur" mit ca 10mio Datensätzen getestet. Dauert 2-5 Sekunden.


----------

