Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate: Collections of Collections

Tags:

This is a problem I keep on running into:

I would like to have hibernate manage a single table that represents a collection of collections. For example:

  • a Map of Maps
  • List of Sets
  • Map of Lists

Example, I would like to be able to represent this:

class OwningClass {  
    Long entityId;  
    Map<String, List<Element>> mapOfLists;
}

class Element {
    String data_1;
    boolean data_2;
}

as a single table:

OWNER (Foreign key to the owner of this element) 
MAP_KEY (varchar(30) )
LIST_INDEX (int)
ELEMENT_DATA_1 (varchar(1020)
ELEMENT_DATA_2 (bit)

It doesn't seem possible without a custom hibernate code, which I don't mind. But I was hoping someone had some guidance on what that custom code should look like.

  • Should I extend AbstractPersistentCollection?
  • CompositeUserType?

Its possible to manage if multiple tables are o.k. but obviously that is lame from the db perspective.

like image 302
Pat Avatar asked Feb 13 '09 07:02

Pat


People also ask

What are collections supported by Hibernate?

" The persistent collections injected by Hibernate behave like HashMap , HashSet , TreeMap , TreeSet or ArrayList , depending on the interface type."

What is Hibernate bag collection?

A Bag is a java collection that stores elements without caring about the sequencing, but allow duplicate elements in the list. A bag is a random grouping of the objects in the list. A Collection is mapped with a <bag> element in the mapping table and initialized with java. util. ArrayList.

Which collection is used in JPA?

JPA allows three kinds of objects to store in mapping collections - Basic Types, Entities and Embeddables.


1 Answers

Found the answer on https://xebia.com/blog/mapping-multimaps-with-hibernate/

This is a long blog post from 11 years ago. The key code is:

public class MultiMapType implements UserCollectionType {

public boolean contains(Object collection, Object entity) {
    return ((MultiMap) collection).containsValue(entity);
}

public Iterator getElementsIterator(Object collection) {
    return ((MultiMap) collection).values().iterator();
}

public Object indexOf(Object collection, Object entity) {
    for (Iterator i = ((MultiMap) collection).entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();    
        Collection value = (Collection) entry.getValue();
        if (value.contains(entity)) {
            return entry.getKey();
        }
    }
    return null;
}

public Object instantiate() {
    return new MultiHashMap();
}

public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister) throws HibernateException {
    return new PersistentMultiMap(session);
}

public PersistentCollection wrap(SessionImplementor session, Object collection) {
    return new PersistentMultiMap(session, (MultiMap) collection);
}

public Object replaceElements(Object original, Object target, CollectionPersister persister, Object owner, Map copyCache, SessionImplementor session) throws HibernateException {

    MultiMap result = (MultiMap) target;
    result.clear();

    Iterator iter = ( (java.util.Map) original ).entrySet().iterator();
    while ( iter.hasNext() ) {
        java.util.Map.Entry me = (java.util.Map.Entry) iter.next();
        Object key = persister.getIndexType().replace( me.getKey(), null, session, owner, copyCache );
        Collection collection = (Collection) me.getValue();
        for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
            Object value = persister.getElementType().replace( iterator.next(), null, session, owner, copyCache );
            result.put(key, value);
        }
    }

    return result;
}

}

There was also some talk over here: Multimap in Hibernate

like image 151
Pat Avatar answered Sep 16 '22 15:09

Pat