I am struggling for almost a week of how to store a HashMap using JPA in Play. All the other attributes are stored, only the HashMap has zero elements (is empty).
public class ImageModel extends Model {
@Id
private String id;
private String url;
@ElementCollection(targetClass = java.lang.String.class)
@MapKeyClass(java.lang.String.class)
private Map<String,String> tags = new HashMap<>();
// the method for adding keys and values to the HashMap
public void add(String key, String value){
tags.put(key,value);
this.save();
}
}
I also tried to annotate with:
@ElementCollection(fetch=FetchType.LAZY)
So, my only guess for now is that I have not configured well Play. (I must say that I am using Play2 and haven't configured anything, except deleting "#" (comment mark) in front of database settings).
On Play documentation says: "There is no built-in JPA implementation in Play 2.0". Could be that the case?
Update: I have made some research and said that could be because I'm using the default database from Play - H2. I tried with MySQL - video how to do it , but again it saves only the id and url. I looked in MySQL database and table with the name of the class had only 2 attribute (id and url), no trace of my HashMap.
Update2: Added a print screen - with database query.
Update3: The sample "computer-database-jpa" from Play is working fine, so the JPA should be fine, but that sample didn't used a Map (HashMap). I even changed hibernate with EclipseLink, but still not working. :( (although, all the basic types attributes are in database)
Here's how I implemented a HashMap using your models.
@Entity
public class ImageModel extends Model {
//All your fields, etc.
@ManyToMany(mappedBy = "imagesWithTag")
@MapKey(name = "name")
public Map<String,Tag> tags = new HashMap<String,Tag>();
}
@Entity
public class Tag extends Model {
// All your fields, etc.
public String name;
public String value;
@ManyToMany
public List<ImageModel> imagesWithTag = new ArrayList<ImageModel>();
}
I decided to go with Eric's suggestion of creating an entire model for Tag, as to make queries easily, but there are times where being able to use the functionalities of a Map will help a lot. This should work for EnumMaps too.
public void addTag(String tagName, String value) {
Tag tag = Tag.finderTag.where().eq("name", tagName).eq("value", value).findUnique();
if(tag == null) {
tag = Tag.newTag(tagName, value);
}
this.tags.put(tag.name, tag);
this.saveManyToManyAssociations("tags");
}
public static List<ImageModel> getImagesWithTag(String tagName, String tagValue) {
Tag tag = finderTag.where().eq("name", tagName).eq("value", tagValue).findUnique();
List<ImageModel> images = new ArrayList<ImageModel>();
for(ImageModel model : tag.imagesWithTag) {
images.add(model);
}
return images;
}
I have seen barely anything about using Maps in Play Framework models, so I decided to create a small sample project (Play 2.1.1) to toy around with and further demonstrate map use.
https://github.com/Raymond26/play-framework-demos/tree/master/PlayMap
I think the real question here is:
Why store these tags in a Map? I guess it will be some kind of key->value
pair like "author"->"John Smith"
, "theme"->"Animals"
, etc. right?
IMHO, you should have a type Tag
:
@Entity
class Tag {
@Id
private Long id;
private String name;
private String value;
// getters, setters, hashCode, equals, etc.
// ...
}
and have a relationship in ImageModel
:
public class ImageModel extends Model {
// ...
@ManyToMany
private Set<Tag> tags;
// ...
}
Here you have a strong typed collection which make really explicit what the relation is.
This way, you could add some interesting stuff on Tag
like a unique constraint, some validation (JSR303), additionnal fields, Javadoc, unit tests, etc.
Also, this allow you to do some useful queries easily, such as:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With