JPA Hibernate and having ElementCollection for Map - java

Can we have an ElementCollection annotation on a field with collection within a collection?
#ElementCollection
private Map<String, List<String>> mappedData = new HashMap<String, List<String>>();
I am getting MappingException at the moment with this so not sure if there are additional annotations or code involved or if I have to make a new class and perhaps use Embeddable and Embedded

You can use UserType or Atribute Converter with JPA attached to your collection I believe. I have never tested it on collection but I believe it is worth the shot:
#ElementCollection
// applies to each element in the collection
#Convert(YourCustomConverter.class)
private Map<String, List<String>> mappedData = new HashMap<String, List<String>>();
When it comes to Hibernate you can try something like this UserCollectionType:
http://www.javalobby.org/java/forums/m91832311.html

Related

Spring Boot Map with Map Key

I am trying to create a
Map<String,Map<Map<String,String>,String>> properties2
as a configurable property with Spring Boot properties file.
I have been previously been able to get a :
Map<String, Map<String,String>> properties
populated with
properties.[A].B=C
where A is the first key and B the second key with a value of C.
I have already tried
properties2.[A].[B=C]=D
which doesn't allow the later components to start although it doesn't throw errors
Does anyone know how I can populate the properties2 map correctly?
you can nest properties as following
private final Map<String, Map<String, Map<String, String>>> namespace = new HashMap<>();
namespace.[foo].[bar].a=alpha
May be you have error here Map,String>> properties2
as you you're using Map<String,String> as as key try this instead Map<String, Map<String, Map<String, String>>>

How to add a HashMap<Object, String> in an entity class?

I am trying to create a sample Report card application and want to persist a map between subject and student's grade
This is my scorecard class:
#Entity
public class ScoreCard {
#NotNull #ElementCollection #ManyToMany(cascade=CascadeType.ALL)
private Map<Subject, String> gradesForMainSubject = new HashMap<Subject, String>();
}
But when trying to save data I always end up with
Caused by: org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: gradesForMainSubject
Subject itself is a Managed entity (annotated by #Entity). Any suggestions on how can I move forward.
You cannot use both #ElementCollection and #ManyToMany at the same time for a collection field.
If the values of your collection are entities, then you can use either one of the 2: #OneToMany or #ManyToMany
If the values of your collection are non-entities, then you must use #ElementCollection.
In your case, the values of your map are String which are not entities. Therefore you need to use #ElementCollection. Remove the #ManyToMany mapping. This rule should be followed, regardless of whether you map key is an entity or not.

How to access List inside Map in Thymeleaf?

Consider the following map,
Map<String, List<String>> map=new HashMap<>();
I would like to put values into this map using thymeleaf. Now, how to insert list items into the map in thymeleaf.
For, Map<String,String> we would write something like map['key']=val;
How to do it for lists?
One way, I thought was keeping the List<String> in a class. For example,
class ListWrapper
{
public List<String> list=new ArrayList<>();
// setter and getter methods
}
and then write the map as
Map<String, ListWrapper> map=new HashMap<>();
and insert like this..
map['key'].list[0]='item 1';
map['key'].list[1]='item 2';
Is there any direct way, instead of writing a class unnecessarily?
Thanks in advance.
You don't need to write a class - you can use Guava's ListMulitMap. Check out these examples.

How to Hibernate annotate Map<String, Set<String>> or Map<String, Map<String, String>>

using Hibernate Core 4.1.7, JPA annotations, java 1.7
Easy to fine are examples about Map<String, Entity> reading Hibernate doc on collections, or Map<String, String> here (stackoverflow).
Hard to find are examples on Map<String, Set<String>> (or even Map<String, Map<String, String>> just for curiosity about daisy chaning) why I ask this question here.
All I want is to save entities (accounts) containing named, multi-valued properties (=account attributes).
I have all working with 3 entity types: Account -> #OneToMany -> AccountAttribute -> #OneToMany -> AccountAttributeValue
But wrapping native Java types with my own Classes seems a bit silly to me. Cloning the Map<String, String> example I would like to have something like
#Entity
public class Account {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="key")
private Long key;
#ElementCollection(fetch=FetchType.EAGER)
#JoinTable(name = "Attribute",
joinColumns = #JoinColumn(name = "fkAccount"))
#MapKeyColumn(name = "name")
// next line is working for Map<String, String>, but not here!
#Column(name = "value")
private Map<String, Set<String>> attributes = new HashMap<String, Set<String>>();
// ... omitting: constructor, getters, setters, toString()
}
Which gives me
Initial SessionFactory creation failed: org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: Attribute, for columns:[org.hibernate.mapping.Column(attributes)]
As DB layout I have created 2 Tables.
- Table Account just having a key to point foreign key to
- Table Attribute containing named value in each line.
E.g. for multivalued attributes I thought of it containing 2 lines with same fkAccount and name but different value - yes, I could have normalized even more, but I want to read my data in acceptable time :-)
CREATE TABLE IF NOT EXISTS `foo`.`Account` (
`key` INT NOT NULL AUTO_INCREMENT ,
...
CREATE TABLE IF NOT EXISTS `foo`.`Attribute` (
`fkAccount` INT NOT NULL ,
`name` VARCHAR(45) NOT NULL ,
`value` VARCHAR(45) NOT NULL
...
Any hints or alternate DB layout proposals appreciated.
EDIT - SOLVED
Solution from Tom (as far as I understood) working for me
Thanky you guys, what an experience, solution in 1 day!
The table layout just mentioned above in my question works now with this classes.
#Entity
public class Account {
/* ... omitting "key", see as above */
/* NEW: now #CollectionTable
replaces #JoinTable / #MapKeyColumn / #Column from above
*/
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name="AccountAttribute",
joinColumns=#JoinColumn(name="fkAccount"))
private Set<AccountAttribute> attributes = null;
// ... omitting: constructor, getters, setters, toString()
}
and NEW
#Embeddable
public class AccountAttribute {
#Column(name="attributeName")
private String attributeName = null;
#Column(name="attributeValue")
private String attributeValue = null;
// ... omitting: constructor, getters, setters, toString()
}
JPA doesn't give you any way to map collections of collections of anything. You can map primitives, references to entities, embeddables, and collections of any of the preceding things.
Collection there means a set, list, or map; there isn't a multimap type here which would help you.
Therefore, there is sadly no way to map exactly the structure you want to map.
I think the closest you could come would be to define an embeddable class Attribute, containing a name and a value, then map a Set<Attribute>. You could then convert this to a Map<String, Set<String>> in code.
It's a shame there's no way to do this. I assume the JPA spec authors either didn't think of it, or thought it was an obscure enough corner case that it wasn't worth dealing with.
There's two ways to model this in the database, and it comes down to how many tables you want. If you want three, then the way you have working is basically right, although you could trim it to two entities (Account and AccountAttribute) where AccountAttribute contains a Set of values.
You can't model it with three tables and just an Account entity, because you don't have enough identifiers. The VALUE table would have to have a compound key made up of the account id and some kind of attribute key, your tables would have to look like:
ACCOUNT (id, ...)
ACCOUNT_ATTRIBUTE(account_id, account_attribute_id, ...)
ACCOUNT_ATTRIBUTE_VALUE(account_id, account_attribute_id, value, ...)
if AccountAttribute is an entity, then it has an ID. If not, it doesn't, and so how would you key the ACCOUNT_ATTRIBUTE_VALUE table?
This is borne out by the JPA spec, as mentioned in this other answer.
Now, you COULD do this in two tables with just an Account entity, by collapsing that Set in to some serialized form and persisting it as binary, or XML, or whatever. Not sure if that's worth the effort to you, but the column you sketched out (value varchar(45)) is almost certainly not long enough.

How to persist a Map<String, List<Object>> in Hibernate

I've got a Map containing MyObject instances. The MyObject class uses JPA to persist its fields:
#OneToMany(cascade = CascadeType.ALL)
#LazyCollection(LazyCollectionOption.FALSE)
private Map<String, MyObject> results = new HashMap<String, MyObject>();
We changed the value stored by the Map to a List:
private Map<String, List<MyObject>> results = new HashMap<String, List<MyObject>>();
But upon launching we receive a stack trace:
Caused by: org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: com.me.myapp.MyObject.results[java.util.List]
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1150)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:680)
at org.hibernate.cfg.annotations.MapBinder$1.secondPass(MapBinder.java:107)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:66)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1221)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:383)
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1206)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:673)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334)
... 30 more
Does Hibernate not support persisting a Map containing (as values) List types? Or are my annotations incorrect? I haven't found this particular configuration in any of the documentation or examples.
The objects stored in the map must be the target object of the oneToMany association (always mapped). You can't store arbitrary objects or collections there.
Personally, I don't think this is a good use of Hibernate. There's no abstraction here. It would make sense if you had a model object with a one-to-many relation expressed as a child List as a data member in the parent.
My advice? Don't use Hibernate. Use straight JDBC, Spring's JDBC template, or something like iBatis.
ORM stands for "Object Relational Mapping". You have tables, so you've got the relational part. You've got data that you can assign to columns in tables.
But it sounds to me like you've got no Objects. So why use Hibernate?

Categories

Resources