Search code examples
javahibernate-mappinghibernate-annotations

How to map a collection Map<String,List<String>> type using Hibernate


The question was to persist the following class using Hibernate .

Public class Album{
Private int albumid;
Private String aname;
Private Map<String,List<String>> photos;
}

I have Tried this

@Entity
public class Album {
    @Id
    private int albumId;
    @Column(name= "Album_Name")
    private String aname;
    
    @ElementCollection
    @MapKeyColumn(name= "Event_Name")
    @Column(name="Values")
    private Map<String, List<String>> photos;

But it is showing errors such as


    Exception in thread "main" org.hibernate.MappingException: Could not determine type for: java.util.List, at table: Album_photos, for columns: [org.hibernate.mapping.Column(Values)]
        at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:336)
        at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:310)
        at org.hibernate.mapping.Collection.validate(Collection.java:315)
        at org.hibernate.mapping.IndexedCollection.validate(IndexedCollection.java:89)
        at org.hibernate.cfg.Configuration.validate(Configuration.java:1362)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1849)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
        at com.wipro.Insert.main(Insert.java:17)


Solution

  • This mapping is not going to work in Hibernate ORM.

    The reason is that you are trying to have two nested collections of elements and this is not supported by Hibernate ORM (first collection is the Map and the second collection is the the List).

    You have to use entities.

    You can obtain something similar to an @ElementCollection with the following mapping:

    
    @Entity
    public static class PhotoEvent {
        @Id
        @Column(name = "Event_Name")
        public String eventName;
    
        @ElementCollection
        @Column(name = "`Values`")
        public List<String> values;
    
        @ManyToOne
        public Album album;
    ...
    // getter/setter/hascode/equals...
    }
    
    
    @Entity
    public static class Album {
        ...
        
        @OneToMany(mappedBy = "album", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
        @MapKey(name = "eventName")
        public Map<String, PhotoEvent> photoEvents;
        
        ...
    }
    
    

    Note that I set FetchType.EAGER because it emulates an @ElementCollection but you will probably want to set it to LAZY (the default).

    You will find more details about this type of mapping in the Hibernate ORM documentation.