Mapping a complex Map in JPA - java

i just can't obtain a persistence with an entity which has a field like this:
private Map<String, List<String>> filterValueRange;
i've tried so far:
#ElementCollection
#JoinTable(name="ATTRIBUTE_VALUE_RANGE", joinColumns=#JoinColumn(name="ID"))
#MapKeyColumn (name="Filter_Id")
#Column(name="FILTER")
private Map<String, List<String>> filterValueRange;
But it seems there is still something missing.
Can anybody point me to the right direction?
I'm using jpa as interface, but there's Hibernate under the hood.
thanks!

Mapping nested collection relationship is not supported with JPA however you can easily overcome this by changing the object model a little, for example:
#OneToMany(mappedBy = "parent")
#MapKeyColumn (name="Filter_Id")
private Map<String, ValueRange> filterValueRange;
and in the corresponding ValueRange entity:
#ManyToOne
private Parent parent;
Alternatively you may also take a look at the following post:
JPA Map<String,String[]> mapping

I don't believe it is possible. What you are trying to achieve is to map element collection of element collections.
In case I am wrong, you should use the
#CollectionTable annotation to define your jointable.
But I think you need to define Embedable that represent value range and has its own ElementCollection of values. Than you can map this embedable to your filterValueRange and access the list of values through it.
If you don't need to query by your filterValueRange you can serialize it simply to Blob.

Related

Make hibernate collections a HashMap instead of List or Set

Is there any way to make hibernate OneToMany collections a Map of id to entity, rather than List or Set?
take a look on #MapKey JPA anotation...
can't test it right now, but it's should be something like
#OneToMany(mappedBy="user")
#MapKey
private Map<Integer, Order> orders;

How to persist a map inside a map in Hibernate?

So I have a class similar to this
public class MyClass{
...
#ElementCollection
private Map<Long,Map<Long,Double>> Vs = new HashMap<Long, Map<Long,Double>>();
...
}
This returns an error when I try to persist the class:
org.hibernate.MappingException: Could not determine type for: java.util.Map, at table: MyClass_Vs, for columns: [org.hibernate.mapping.Column(Vs)]
I think the error is because there is a map inside the original map that has the annotation of #ElementCollection. Any idea of how to solve this?
I really doubt Hibernate will be able to handle this type of mapping for you with just #ElementCollection. You probably will need to define a new composite key, containing both of those Long map keys as #Id fields, then use an element collection on a Map<CompositeLong, Double>. Granted, I'm making some assumptions about what those Long values represent, but it's hard to tell without more context.

SortedMap Key Persistance in Hibernate

I'm hoping someone can help me with my hibernate issue as I've been banging my head against Google for around an hour without result.
So the issue is that I have a SortedMap in a class, using Integer as the Key (and its natural built-in compareTo method) and another class as the value type. I'm using the key to keep the user-defined order of the value type and trying to get Hibernate to persist this.
For whatever reason, Hibernate has defaulted to disregarding the key I have inputted and instead using the value type's primary key as the key instead. When I load my Map back out of the database all of my keys have been changed in this way.
Definition of the Map is shown below (I'm using annotation-style Hibernate);
#ManyToMany(cascade = CascadeType.ALL)
#MapKey
#Sort(type = SortType.NATURAL)
private SortedMap<Integer, Column> columnOrder;
I can't use the Column type to store the order itself as the Column may be used in many instances of the containing type, with a different key value each time. Any guidance would be most appreciated.
So I found the answer after discovering this StackOverflow question with a similar issue: Sorted map of Java primitives using JPA2 and Hibernate?
By changing the #MapKey annotation to the #MapKeyColumn annotation, I was able to give Hibernate the instruction to persist the key in the column name I specified, as below;
#ManyToMany(cascade = CascadeType.ALL)
#MapKeyColumn(name = "hierarchyOrdering")
#Sort(type = SortType.NATURAL)
private SortedMap<Integer, Column> columnOrder;
Thanks for the help.
From the javadoc of javax.persistence.OrderColumn:
Specifies a column that is used to maintain the persistent order of a list. The persistence provider is responsible for maintaining the order upon retrieval and in the database. The persistence provider is responsible for updating the ordering upon flushing to the database to reflect any insertion, deletion, or reordering affecting the list.
So it is possible to use a list for that.
The JPA 2.0 spec states in section 2.2 Persistent Fields and Properties:
Collection-valued persistent fields and properties must be defined in terms of one of the following collection-
valued interfaces regardless of whether the entity class otherwise adheres to the JavaBeans
method conventions noted above and whether field or property access is used: java.util.Collection,
java.util.Set, java.util.List[3], java.util.Map. The collection implementation
type may be used by the application to initialize fields or properties before the entity is made
persistent. Once the entity becomes managed (or detached), subsequent access must be through the
interface type.
So it seems as if a SortedMap is not supported by JPA.

Hibernate mapping a UserType inside a Map

I have come across a problem where I cannot persist a Map<UUID, Integer> using Hibernate. I'm not sure how to properly annotate this collection such that it may be properly mapped into our database. We control the schema, so any way this will work will be fine. Do i need to specify what UserType the key is in my Map somehow? Do I need one? I know the Type annotation is used for individual fields. Perhaps not collections? I am receiving the following exception on my call to session.flush()
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.UUID
#ElementCollection
#Type(type="org.hibernate.type.UUIDCharType")
private Map<UUID, Boolean> orderCount = new HashMap<UUID, Integer>();
I believe you will have to write a UserType to handle Map<UUID, Boolean> .. This UserType should then use org.hibernate.type.UUIDCharType to map the key column.

Difference between #OneToMany and #ElementCollection?

What is the difference between using a #OneToMany and #ElementCollection annotation since both work on the one-to-many relationship?
ElementCollection is a standard JPA annotation, which is now preferred over the proprietary Hibernate annotation CollectionOfElements.
It means that the collection is not a collection of entities, but a collection of simple types (Strings, etc.) or a collection of embeddable elements (class annotated with #Embeddable).
It also means that the elements are completely owned by the containing entities: they're modified when the entity is modified, deleted when the entity is deleted, etc. They can't have their own lifecycle.
I believe #ElementCollection is mainly for mapping non-entities (embeddable or basic) while #OneToMany is used to map entities. So which one to use depend on what you want to achieve.
#ElementCollection allows you to simplify code when you want to implement one-to-many relationship with simple or embedded type. For instance in JPA 1.0 when you wanted to have a one-to-many relationship to a list of Strings, you had to create a simple entity POJO (StringWrapper) containing only primary key and the String in question:
#OneToMany
private Collection<StringWrapper> strings;
//...
public class StringWrapper {
#Id
private int id;
private String string;
}
With JPA 2.0 you can simply write:
#ElementCollection
private Collection<String> strings;
Simpler, isn't it? Note that you can still control the table and column names using #CollectionTable annotation.
See also:
Java Persistence/ElementCollection
Basic or Embedded: #ElementCollection
Entities: #OneToMany or #ManyToMany
#ElementCollection:
the relation is managed (only) by the entity in which the relation is defined
table contains id reference to the owning entity plus basic or embedded attributes
#OneToMany / #ManyToMany:
can also be managed by the other entity
join table or column(s) typically contains id references only
#ElementCollection marks a collection. This does not necessarily mean that this collection references a 1-n join.
ElementCollection can override the mappings, or table for their collection, so you can have multiple entities reference the same Embeddable class, but have each store their dependent objects in a separate table.
#ElementCollection
This annotation will be applied when there is a relation with non-entity and these associations relation was HAS-A. Every collection is created with a table and gets relation by Foreign Key.
There are two types of element collections
Index (List, Map)
Non-Index (Set)
Index: The index type collection has a table with 3 columns they are
Key Column (Foriegn Key)
Index Column (Position of data in collection)
Element Column (Data)
Non-Index: The Non-Index type collection has a table with 2 columns they are
Key Column
Element Column
Note: Here it won't have any index column because, Since a SET doesn’t retain the insertion order.
Multiplicity
This is a way to implement the HAS-A relation between two entities and the cardinality ratio depends on their relation.
You can use ElementCollection replace for you use #OneToMany. Example you can have one Project in many versions.
#ElementCollection
#CollectionTable(name="versions",
joinColumns = #JoinColumn(name="projectID"))
#LazyCollection(LazyCollectionOption.FALSE)
#JoinColumn(name="version",nullable = false)
private Set<String> versions;
You also can use #ElementCollection in mapping OGM for array in one collection.
#ElementCollection(fetch = FetchType.EAGER)
private Set<String> researchAreas;

Categories

Resources