Reputation: 129
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:
key
in the mapvalue
in the map associated to the column key
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.
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.
Any answer of my question and other suggestions to the approach to be used in our use case are both appreciated.
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
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:
Upvotes: 1
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