# Hibernate Map<String,String> mit Annotations mappen



## RaoulDuke (28. Mrz 2012)

Hallo zusammen,

ich versuche ein Hibernate XML Mapping auf Annotationen umzustellen, leider konnte ich für einen konkreten Fall noch nichts passendes finden. Ich habe eine Klasse Event, die hat eine Map<String,String> mit Attributen. Via XML lässt sich das sehr komfortabel machen:


```
<map access="field" name="attributes" table="eventattributes" lazy="false">
            <key column="id"/>
            <index column="key" length="1024" type="string"/>
            <element column="value" length="4096" type="string"/>
        </map>
```

Mit Annotationen krige ich es nicht hin, mein aktueller Versuch sieht so aus:


```
@ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
    @MapKeyClass(String.class)
    @AttributeOverrides({
            @AttributeOverride(name="key", column=@Column(name = "key", length = 1024)),
            @AttributeOverride(name="value", column=@Column(name = "value", length = 4096))
    })
    private Map<String,String> attributes = new TreeMap<String,String>();
```

Das führt zu folgender Exception:


```
Caused by: org.hibernate.MappingException: Repeated column in mapping for collection: xxx.domain.EventDO.attributes column: count
   at org.hibernate.mapping.Collection.checkColumnDuplication(Collection.java:341)
```

Diese tritt auf sobald ich die @AttributeOverrides mit angebe. Ohne diese läuft die Applikation zwar, meine Querys liefern aber jedes Event n-mal zurück.

Mich wundert es ein wenig das es so schwer ist etwas so simples per Annotations zu mappen. Mir ist es dabei auch egal ob es JPA oder Hibernate Annotations sind.

Grüße,

Sven


----------



## RaoulDuke (29. Mrz 2012)

Ich bin mittlerweile bei diesem Ansatz hier:


```
@ElementCollection(fetch = FetchType.EAGER)
    @MapKeyColumn(name = "key", length = 1024)
    @Column(name = "value", length = 4069)
    private Map<String,String> attributes = new TreeMap<String,String>();
```

Es legt wie erwartet eine Tabelle event_attributes an, mit den Spalten event_id, key, value. Die Felder haben auch die richtige Größe. Ich habe jetzt in meiner Tabelle ein Event mit 20 Attributen, jetzt liefert mit eine Suche danach das gleiche Event 20 mal zurück, einmal pro Attribut. Laut SQL Ausgabe macht er einen Join über die neue Tabelle. Was da der Sinn sein soll erschließt sich mir bisher nicht, ich hätte erwartet das er die Zeilen aus der Tabelle "events" lädt und dann über die ID jedes gefundenen Event die Attribute aus der anderen Tabelle holt. 

Grüße,

Sven


----------



## RaoulDuke (29. Mrz 2012)

So, es funktioniert nun:


```
@ElementCollection(fetch = FetchType.EAGER)
    @Fetch(value = FetchMode.SELECT)
    @MapKeyColumn(name = "key", length = 1024)
    @Column(name = "value", length = 4069)
    private Map<String,String> attributes = new TreeMap<String,String>();
```

Wenn man den FetchMode via der Hibernate Annotation org.hibernate.annotations.Fetch auf Fetchmode.SELECT stellt, dann lässt er das mit dem Join sein sondern lädt erst die Events und macht dann pro Event einen select auf die Tabelle mit den Attributen. Dann erhält man keine doppelten Ergebnisse mehr. 

Ich verstehe ja das ein Join doppelte Objekte zurückliefert, das steht ja auch in der FAQ, warum er in diesem Fall aber per Default einen Join baut ist mir nicht verständlich denn es hat eigentlich überhaupt keinen Nutzen. 

Sven


----------

