fayndee
fayndee

Reputation: 129

With JPA, is it possible to map relational tables to java.util.Map as @Entity?

About the question

First time I ask question here, so I'm trying to be clear about my question. I'm not asking how to map relationships using java.util.Map, nor to use java.util.Map as an @Embedded object. What I really want to know is the possibility of using java.util.Map as the mapped @Entity.

Samples are always better than thousands of words. Here is what I want in short:

<entity class="java.util.HashMap" access="KEY">
    <table name="TABLE_1"/>
    <attributes>
        <id name="id">
            <column name="COL_ID" />
        </id>
        <basic name="attr1" >
            <column name="COL_1" />
        </basic>
        <basic name="attr2" >
            <column name="COL_2" />
            <temporal>DATE</temporal>
        </basic>
        ...
    </attributes>
</entity>

As described above, the content of relational table TABLE_1 is mapped to class java.util.HashMap where:

In another word (shorter version):

Well in Java, it would be something like:

@Entity(name="TABLE_1")
public class View extends HashMap<String, Object> {
    // no attributes here because the columns will be mapped as key of this class

    // and the value type here is Object because the type of the columns can be anything (i.e. varchar, integer, timestamp etc.)
}

I know this is not a typical kind of ORM mapping, and it is probably not the purpose of JPA at all. But it is the first thing come out of my mind in our use case.

Use case

We have a relational database with a cup of tables and we also have a few views defined based on these tables. What we are trying to do right now is to develop a web based UI to work with the views defined in the database.

The more or less 'tricky' thing here is that the definition of the view are not completed yet, and we will certainly need to modify and/or add more views in the future. But the business requirement remains the same: allow user to query, filter and edit the views and eventually to perform other actions (like audit, add comments for example).

In this case, we need to be able to add/remove views to/from the application via configuration and use a common approach to handle a set of actions usable on different views. And part of the solution is to use a common container to hold data that blurs out "what a view really is". From where comes the idea to use a java.util.Map.

The reason I'm looking for using JPA mappings in our use case is the ability to use a more code-friendly criteria API, type conversion and avoid to use low level JDBC codes which are probably hard to maintain.

Helps needed

Any answer of my question and other suggestions to the approach to be used in our use case are both appreciated.

[Edited] Solution (with Alan Hay's suggestion)

Use Hibernate's Dynamic models feature, I can easily do something like the following:

<hibernate-mapping>
    <!-- Specify the 'entity-name' instead of 'class' here to activate the dynamic model -->
    <class entity-name="DynamicEntity" table="TABLE1">
        <id name="id" column="COL_ID" type="long" />
        <property name="attribute1" column="COL_1" type="string" />
        <property name="attribute2" column="COL_2" type="string" />
        <property name="attribute3" column="COL_3" type="date" />
    </class>
</hibernate-mapping>

Then everything is handled smoothly by Hibernate:

Session hibernateSession = ...;
Map dynamicEntity = (Map) hibernateSession.get("DynamicEntity", 1L);
System.out.println(dynamicEntity.getClass());
System.out.println(dynamicEntity);

// output
// class java.util.HashMap
// {$type$=DynamicEntity, id=1, attribute1=foo, attribute2=bar, attribute3=2013-11-19}

Upvotes: 2

Views: 1910

Answers (2)

Alan Hay
Alan Hay

Reputation: 23246

Yes and no. There is nothing in the JPA spec however if you are using Hibernate then the Hibernate 'Dynamic Models' feature seems to be exactly what you are looking for:

http://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-dynamicmodels.html

Upvotes: 1

V G
V G

Reputation: 19002

No, you cannot do that with the java.util.Map as it is only an interface. Also with a HashMap you cannot do it, as it does not have an ID column (beside other problems). But you can create an entity MapEntity that contains a private Map internalMap; and that implements the Map interface, manipulating the contained internalMap in each of the Map's interface, obtaining a similar result. With this idea I don't know what the consequences are, when the MapEntity is used in other entities, but probably you shouldn't get any problems.

Example (View is in this case an @Embeddable. If View is an entity, use the @MapKey annotation

public class MapEntity implements Map<Integer, View> {


    //add the id column...


    @ElementCollection//+other mapping configuration like @CollectionTable (name = "ViewMap", joinColumns = @JoinColumn (name = "view_id"))
    private Map<Integer, View> internalMap = new HashMap<Integer, View>;


    //implementation of a method from the Map interface. The other methods are simply delegated to the internalmap.
    @Override
    public View put(Integer key, View value) {
      internalMap.put(key, value);
    }

}

Upvotes: 0

Related Questions