Good day! I'm having a problem when updating an entity. When I click the "update" button, the changes are saved. However, when I go a different page, the recently changed (or added) items are there but the old items (that should be changed or removed) are also there. Particularly the relatedTags (the name and notes are updating just fine). Why is it not persistent or permanent? Here are the models:
Tag model:
package models;
import java.sql.Timestamp;
import java.util.*;
import javax.persistence.*;
import javax.validation.*;
import play.data.Form;
import play.data.validation.Constraints.*;
import play.db.ebean.*;
import play.db.ebean.Model.Finder;
import scala.Int;
#Entity
public class Tag extends Model{
#Id
private int id;
#Required
#MaxLength(value=100)
#Column(unique=true)
private String name;
#MaxLength(value=200)
private String notes;
#OneToMany(cascade=CascadeType.ALL)
public List<RelatedTag> relatedTags = new ArrayList<RelatedTag>();
#Version
public Timestamp lastUpdate;
public static Finder<Integer, Tag> find = new Finder(Int.class, Tag.class);
public Tag() {
}
public Tag(String name, String notes){
this.name = name;
this.notes = notes;
}
public Tag(int id, String name, String notes, List<RelatedTag> relatedTags) {
this.id = id;
this.name = name;
this.notes = notes;
this.relatedTags = relatedTags;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
public List<RelatedTag> getRelatedTags() {
return relatedTags;
}
public void setRelatedTags(List<RelatedTag> relatedTags) {
this.relatedTags = relatedTags;
}
public static List<Tag> all() {
return find.all();
}
public static void create(Tag tag){
tag.save();
}
public static void delete(int id){
find.ref(id).delete();
}
public static void update(int id, Tag tag) {
tag.update(id); // updates this entity, by specifying the entity ID
}
public static boolean exists(Tag newTag) {
for(Tag allTags : Tag.find.all()) {
if(allTags.getName().equals(newTag.getName()))
return true;
}
return false;
}
}
RelatedTag model
package models;
import java.sql.Timestamp;
import java.util.*;
import javax.persistence.*;
import javax.validation.*;
import play.data.Form;
import play.data.validation.Constraints.*;
import play.db.ebean.*;
import play.db.ebean.Model.Finder;
import scala.Int;
#Entity
public class RelatedTag extends Model {
#Id
public int rtID;
private int id; //same as Tag's id
private String relationship;
private String relatedNotes;
#Version
public Timestamp lastUpdate;
public RelatedTag() {}
public RelatedTag(int id, String relationship, String relatedNotes) {
this.id = id;
this.relationship = relationship;
this.relatedNotes = relatedNotes;
}
public void setId(int id){
this.id = id;
}
public void setRelationship(String relationship){
this.relationship = relationship;
}
public void setRelatedNotes(String relatedNotes) {
this.relatedNotes = relatedNotes;
}
public int getId(){
return id;
}
public String getRelationship(){
return relationship;
}
public String getRelatedNotes() {
return relatedNotes;
}
public static void create(List<RelatedTag> rt){
((Model) rt).save();
}
public static boolean exists(String tagRelated) {
for(Tag tag : Tag.find.all()) {
if(tagRelated.equals(tag.getName()))
return true;
}
return false;
}
public static RelatedTag findByLabel(String tagRelated, String relation, String relatedNotes) {
RelatedTag relatedTag = null;
for(Tag tag : Tag.find.all()) {
if(tagRelated.equals(tag.getName())) {
relatedTag = new RelatedTag(tag.getId(), relation, relatedNotes);
}
}
return relatedTag;
}
public static Tag findTag(int id) {
for(Tag tag : Tag.find.all()) {
if(id == tag.getId())
return tag;
}
return null;
}
}
And here is where the updating happens.
Form<Tag> filledForm = tagForm.fill(Tag.find.byId(id)).bindFromRequest();
Tag editedTag = RelatedTag.findTag(id);
if(filledForm.hasErrors()) {
return badRequest(editTagForm.render(user, editedTag, filledForm, tags));
}
else {
List<RelatedTag> relatedTagsAlloc = new ArrayList<RelatedTag>();
java.util.Map<String, String[]> map = request().body().asFormUrlEncoded();
String[] relatedTags = map.get("relatedTags.tag.name");
String[] relationship = map.get("relatedTags.relationship");
String[] relatedNotes = map.get("relatedTags.relatedNotes");
if (relatedTags != null) {
for (int i = 0; i < relatedTags.length; i++) {
if (RelatedTag.exists(relatedTags[i].trim().toLowerCase().replaceAll("\\s+", " "))) {
relatedTagsAlloc.add(RelatedTag.findByLabel(
relatedTags[i].trim().toLowerCase().replaceAll("\\s+", " "), relationship[i], relatedNotes[i].trim()));
} else {
Tag unknown = new Tag(relatedTags[i], "");
Tag.create(unknown);
relatedTagsAlloc.add(RelatedTag.findByLabel(
relatedTags[i].trim().toLowerCase().replaceAll("\\s+", " "), relationship[i], relatedNotes[i].trim()));
}
}
editedTag.getRelatedTags().clear();
}
editedTag.setName(filledForm.get().getName().toLowerCase().replaceAll("\\s+", " "));
editedTag.setRelatedTags(relatedTagsAlloc);
editedTag.update();
Application.log(user, editedTag, action);
writeToFile(editedTag);
return ok(summary.render(user, editedTag));
}
What have I been doing wrong? Please help me fix this I really need your guidance. Thank you very much!
Related
I am using JSON-B for output object to json and there is a circular reference in the object (please do not ask me to remove the circular reference), sample code as follows
The Person class contains a list of Property
and the Property class reference back the person which form a circular reference.
In the first print the json can be output, however in the second print statement, stack overflow error due to touch the circular reference of the object, I do not want to use #JsonbTransient to ignore any of them, how can I solve this?
I am expecting the json output as
{"id":1,"name":"Jhon","propertyList":[{"person":1, "propertyName":"Palace"},{"person":1, "propertyName":"Apartment"}]}
Sample Code:
import java.util.ArrayList;
import java.util.List;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class JsonTest {
public static void main(String[] args) throws InterruptedException {
Person person = new Person(1, "Jhon");
Jsonb jsonb = JsonbBuilder.create();
//no error as no property is added
System.out.println("jsonPerson without property: " + jsonb.toJson(person));
Property p1 = new Property();
p1.setPropertyName("Palace");
p1.setPerson(person);
Property p2 = new Property();
p2.setPropertyName("Apartment");
p2.setPerson(person);
person.getPropertyList().add(p1);
person.getPropertyList().add(p2);
/**
* stackoverflow here
*/
System.out.println("jsonPerson with property: " + jsonb.toJson(person));
}
public static class Property {
private Person person;
private String propertyName;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getPropertyName() {
return propertyName;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
}
public static class Person {
private int id;
public Person() {
super();
}
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
private String name;
private List<Property> propertyList = new ArrayList<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Property> getPropertyList() {
return propertyList;
}
public void setPropertyList(List<Property> propertyList) {
this.propertyList = propertyList;
}
}
}
Finally I give up using JSON-B and instead use Jackson, use the annotation #JsonIdentityInfo here is my solution for information:
import java.util.ArrayList;
import java.util.List;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonTest {
private static Person person = null;
private static List<Property> propertyList = new ArrayList<>();
public static void main(String[] args) throws Exception {
person = new Person(1, "Jhon");
propertyList.add(new Property(1, person, "Palace"));
propertyList.add(new Property(2, person, "Apartment"));
person.setPropertyList(propertyList);
jacksonTest();
//jsonbTest();
}
private static void jacksonTest()
throws Exception
{
String result = new ObjectMapper().writeValueAsString(person);
System.out.println("result: " + result);
}
private static void jsonbTest()
throws Exception
{
Jsonb jsonb = JsonbBuilder.create();
/**
* stackoverflow here
*/
System.out.println("jsonPerson with property: " + jsonb.toJson(person));
}
public static class Property extends BaseEntity {
private Person person;
private String propertyName;
public Property(int id, Person person, String propertyName) {
super();
setId(id);
this.person = person;
this.propertyName = propertyName;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getPropertyName() {
return propertyName;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
}
public static class Person extends BaseEntity {
public Person() {
super();
}
public Person(int id, String name) {
super();
setId(id);
this.name = name;
}
private String name;
private List<Property> propertyList = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Property> getPropertyList() {
return propertyList;
}
public void setPropertyList(List<Property> propertyList) {
this.propertyList = propertyList;
}
}
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public static abstract class BaseEntity {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
}
Jackson output:
result: {"id":1,"name":"Jhon","propertyList":[{"id":1,"person":1,"propertyName":"Palace"},{"id":2,"person":1,"propertyName":"Apartment"}]}
I am trying to update a list of a company class I created in Play Framework.
It all works until i get to the company.update(), which doesn't save to the database as it should.
Here is my Company class:
package models;
import io.ebean.Finder;
import io.ebean.Model;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Company extends Model {
#Id
public Integer id;
public String code;
public String name;
public String adress;
public String fiscalCode;
public String bankAccount;
public static Finder<Integer, Company> find = new Finder<>(Company.class);
public String getFiscalCode() {
return fiscalCode;
}
public void setFiscalCode(String fiscalCode) {
this.fiscalCode = fiscalCode;
}
public String getBankAccount() {
return bankAccount;
}
public void setBankAccount(String bankAccount) {
this.bankAccount = bankAccount;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
}
And here are my update and edit methods:
public Result editCompany(Integer id){
Company company = Company.find.byId(id);
if(company == null)
{
return notFound("Company not found");
}
Form<Company> companyForm = formFactory.form(Company.class).fill(company);
return ok(editCompany.render(companyForm));
}
public Result updateCompany(){
Form<Company> companyForm = formFactory.form(Company.class).bindFromRequest();
if(companyForm.hasErrors())
{
flash("danger","Please Correct the Form Below");
return badRequest(editCompany.render(companyForm));
}
Company newcompany = companyForm.get();
Company company = Company.find.byId(newcompany.id);
if (company == null) {
flash("danger", "Book not found");
redirect(routes.CompanyController.indexCompanies());
}
company.code = newcompany.code;
company.name = newcompany.name;
company.adress = newcompany.adress;
company.fiscalCode = newcompany.fiscalCode;
company.bankAccount = newcompany.bankAccount;
company.update();
flash("success","Company Details Updated Successfully");
return redirect(routes.CompanyController.indexCompanies());
}
The new company entity has updated values, but they don't save in the database. I checked by printing to the console company.name.
I hope you can help me. Thank you!
I seem to have figured it out.
The problem goes away after using getters and setters and doing a recompile. Therefore,
company.code = newcompany.code;
company.name = newcompany.name;
company.adress = newcompany.adress;
company.fiscalCode = newcompany.fiscalCode;
company.bankAccount = newcompany.bankAccount;
becomes
company.setCode(newcompany.getCode());
company.setName(newcompany.getName());
company.setAdress(newcompany.getAdress());
company.setFiscalCode(newcompany.getFiscalCode());
company.setBankAccount(newcompany.getBankAccount());
My goal is to clone entity 'Product' with all its filters.
For example, I have an entity (getters and setters omitted for simplicity):
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ElementCollection()
private List<Filter> filters = new ArrayList<Filter>();
}
And embeddable class:
#Embeddable
public class Filter {
#Column(length = 255, nullable = false)
private String name;
#Column(nullable = false)
private long variant = -1;
}
Now, if I do:
entityManager.detach(product);
product.setId(null);
productService.save(product);
I will get a copy of product entity but with filters from original product. In meanwhile original product will end up with no filters at all..
Thats how filter's table rows looks like:
Before:
product_id; name; variant
217; "f2"; 86
After:
product_id; name; variant
218; "f2"; 86
I tried detach each filter from the list but it gives me error.
How can I make it copy filters with an entity?
Edit: Added full Product and Filter code:
package com.serhiy1.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.SortableField;
import org.joda.time.DateTime;
import com.serhiy1.constraint.LocalePacker;
#Indexed
#Entity
#EntityListeners(ProductListener.class)
public class Product {
public static final int PRICE_PER_ONE = 0;
public static final int PRICE_PER_METER = 1;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long code;
private String name = "";
private String grouping = "";
#Field
#Column(columnDefinition="text")
private String title = "";
#Field
#Column(columnDefinition="text")
private String intro = "";
#Column(columnDefinition="text")
private String content = "";
#Field
#Column(columnDefinition="text")
private String contentHtml = "";
private String locale = "en";
private Long parentId = 0L;
private DateTime time;
private DateTime timeMod;
private Long balanceRequired = 0L;
private Integer index = 0;
#Field(name = "price_sort")
#SortableField(forField = "price_sort")
private Double price = 0.0;
private Integer pricePer;
#Transient
private long childrenCount = 0;
#Transient
private String image = "";
#Transient
private List<String> images = new ArrayList<String>();
#ManyToOne(targetEntity = User.class)
#JoinColumn(nullable = false, name = "user_id")
#LazyCollection(LazyCollectionOption.FALSE)
private User user;
#ManyToOne(targetEntity = Product.class)
#JoinColumn(nullable = true, name = "category_id")
#LazyCollection(LazyCollectionOption.FALSE)
private Product category;
#ElementCollection()
private List<Filter> filters = new ArrayList<Filter>();
#ElementCollection()
private List<Modifier> modifiers = new ArrayList<Modifier>();
public Product() {
}
#Transient
private String _title = "";
#Transient
private String _intro = "";
#Transient
private String _content = "";
#Transient
private String _contentHtml = "";
public void pack(String locale, List<String> locales) {
if(locale.contains("_")) return;
title = LocalePacker.repack(locale, _title, title, locales);
intro = LocalePacker.repack(locale, _intro, intro, locales);
content = LocalePacker.repack(locale, _content, content, locales);
contentHtml = LocalePacker.repack(locale, _contentHtml, contentHtml, locales);
}
public void unpack(String locale) {
_title = LocalePacker.unpackStr(locale, title).getOrDefault(locale, "");
_intro = LocalePacker.unpackStr(locale, intro).getOrDefault(locale, "");
_content = LocalePacker.unpackStr(locale, content).getOrDefault(locale, "");
_contentHtml = LocalePacker.unpackStr(locale, contentHtml).getOrDefault(locale, "");
}
public void copy(String landFrom, String landTo) {
title = LocalePacker.copyLang(title, landFrom, landTo);
intro = LocalePacker.copyLang(intro, landFrom, landTo);
content = LocalePacker.copyLang(content, landFrom, landTo);
contentHtml = LocalePacker.copyLang(contentHtml, landFrom, landTo);
}
public Modifier getModifier(String name) {
for(Modifier m: modifiers) {
if(m.getName().equals(name)) return m;
}
return null;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public long getCode() {
return code == null ? id : code;
}
public void setCode(long code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrouping() {
return grouping;
}
public void setGrouping(String grouping) {
this.grouping = grouping;
}
public String getTitle() {
return _title;
}
public void setTitle(String title) {
this._title = title;
}
public String getIntro() {
return _intro;
}
public void setIntro(String intro) {
this._intro = intro;
}
public String getContent() {
return _content;
}
public void setContent(String content) {
this._content = content;
}
public String getContentHtml() {
return _contentHtml;
}
public void setContentHtml(String contentHtml) {
this._contentHtml = contentHtml;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public long getParentId() {
return parentId;
}
public void setParentId(long parentId) {
this.parentId = parentId;
}
public DateTime getTime() {
return time;
}
public void setTime(DateTime time) {
this.time = time;
}
public DateTime getTimeMod() {
return timeMod;
}
public void setTimeMod(DateTime timeMod) {
this.timeMod = timeMod;
}
public long getBalanceRequired() {
return balanceRequired == null ? 0L : balanceRequired;
}
public void setBalanceRequired(long balanceRequired) {
this.balanceRequired = balanceRequired;
}
public Integer getIndex() {
//return index == null ? 1000 : index;
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public double getPrice() {
return price == null ? 0.0 : price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPricePer() {
return pricePer == null ? PRICE_PER_METER : pricePer;
}
public void setPricePer(int pricePer) {
this.pricePer = pricePer;
}
public long getChildrenCount() {
return childrenCount;
}
public void setChildrenCount(long childrenCount) {
this.childrenCount = childrenCount;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Product getCategory() {
return category;
}
public void setCategory(Product category) {
this.category = category;
}
public List<Filter> getFilters() {
return filters;
}
public void setFilters(List<Filter> filters) {
this.filters = filters;
}
public List<Modifier> getModifiers() {
return modifiers;
}
public void setModifiers(List<Modifier> modifiers) {
this.modifiers = modifiers;
}
public boolean isCategory() { return price < 0; }
#Override
public String toString() {
return "Article{" +
"id=" + id +
'}';
}
}
..
package com.serhiy1.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Transient;
#Embeddable
public class Filter {
#Column(length = 255, nullable = false)
private String name;
#Column(nullable = false)
private long variant = -1;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVariant() {
return variant;
}
public void setVariant(long variant) {
this.variant = variant;
}
}
I made a mini project trying to replicate your issue.
It is a String Boot project with H2 database and JPA (Hibernate implementation).
On startup, Hibernate creates 2 tables:
create table product (
id bigint not null,
primary key (id)
)
and
create table product_filters (
product_id bigint not null,
name varchar(255) not null,
variant bigint not null
)
On product with filters creation, both tables get inserted:
insert
into
product
(id)
values
(1)
and
insert
into
product_filters
(product_id, name, variant)
values
(1, "f1", 1)
After:
entityManager.detach(product);
product.setId(null);
productService.save(product);
Hibernate issues:
delete
from
product_filters
where
product_id=1
which is normal, since filters is an ElementCollection therefore it is totally owned by the entity Product. On productService.save(product) Hibernate detects that filters collection is bound to another Product therefore deletes the old bound (from product_filter table) before creating a new one.
The only way to overcome the deletion is to recreate the collection:
List<Filter> filters = new ArrayList<Filter>();
filters.addAll(oldFilters);
product.setFilters(filters);
To sum up, here is the solution:
// To trigger the fetch
List<Filter> filters = new ArrayList<Filter>(product.getFilters());
entityManager.detach(product);
product.setId(null);
product.setFilters(filters);
productService.save(product);
I'm using Kundera to do the persistence in MongoDB. I can persist some documents in my collection, but everytime that I try to find a specific document by id, I get this error
java.lang.ClassCastException: java.lang.String cannot be cast to com.mongodb.BasicDBList
com.impetus.kundera.persistence.AbstractEntityReader.findById(AbstractEntityReader.java:95)
com.impetus.client.mongodb.MongoEntityReader.findById(MongoEntityReader.java:72)
com.impetus.kundera.lifecycle.states.ManagedState.handleFind(ManagedState.java:com.impetus.kundera.graph.Node.find(Node.java:500)
com.impetus.kundera.persistence.PersistenceDelegator.find(PersistenceDelegator.java:225)
com.impetus.kundera.persistence.PersistenceDelegator.findById(PersistenceDelegator.java:174)
com.impetus.kundera.persistence.EntityManagerImpl.find(EntityManagerImpl.java:263)
My class definition is
package data.additional;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import com.google.common.collect.Lists;
#Entity
#Table(name = "reference", schema = "RcordsDB#pl_records")
public class Reference {
#Id
#Column(name="idReference")
private String idReference;
#Column(name="profile_id")
private String profile_id;
#Column(name="group_id")
private String group_id;
#Column(name="created")
private Date created;
#Column(name="last_modified")
private Date last_modified;
#Column(name="identifiers")
private List<String> identifiers = Lists.newArrayList();
#Column(name="abstractText")
private String abstractText;
#Column(name="tags")
private String tags;
#Column(name="type")
private String type;
#Column(name="source")
private String source;
#Column(name="title")
private String title;
#Column(name="title")
private List<String> authors = Lists.newArrayList();
#Column(name="year")
private Date year;
#Column(name="volume")
private String volume;
#Column(name="issue")
private String issue;
#Column(name="pages")
private String pages;
#Column(name="series")
private String series;
#Column(name="chapter")
private String chapter;
#Column(name="websites")
private String websites;
#Column(name="accesed")
private String accesed;
#Column(name="publisher")
private String publisher;
#Column(name="city")
private String city;
#Column(name="edition")
private String edition;
#Column(name="institution")
private String institution;
#Column(name="editors")
private List<String> editors = Lists.newArrayList();
#Column(name="keywords")
private List<String> keywords = Lists.newArrayList();
#Column(name="doi")
private String doi;
#Column(name="isbn")
private String isbn;
#Column(name="issn")
private String issn;
public String getIdReference() {
return idReference;
}
public void setIdReference(String idReference) {
this.idReference = idReference;
}
public String getProfile_id() {
return profile_id;
}
public void setProfile_id(String profile_id) {
this.profile_id = profile_id;
}
public String getGroup_id() {
return group_id;
}
public void setGroup_id(String group_id) {
this.group_id = group_id;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getLast_modified() {
return last_modified;
}
public void setLast_modified(Date last_modified) {
this.last_modified = last_modified;
}
public List<String> getIdentifiers() {
return identifiers;
}
public void setIdentifiers(List<String> identifiers) {
this.identifiers = identifiers;
}
public String getAbstractText() {
return abstractText;
}
public void setAbstractText(String abstractText) {
this.abstractText = abstractText;
}
public String getTags() {
return tags;
}
public void setTags(String tags) {
this.tags = tags;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getAuthors() {
return authors;
}
public void setAuthors(List<String> authors) {
this.authors = authors;
}
public Date getYear() {
return year;
}
public void setYear(Date year) {
this.year = year;
}
public String getVolume() {
return volume;
}
public void setVolume(String volume) {
this.volume = volume;
}
public String getIssue() {
return issue;
}
public void setIssue(String issue) {
this.issue = issue;
}
public String getPages() {
return pages;
}
public void setPages(String pages) {
this.pages = pages;
}
public String getSeries() {
return series;
}
public void setSeries(String series) {
this.series = series;
}
public String getChapter() {
return chapter;
}
public void setChapter(String chapter) {
this.chapter = chapter;
}
public String getWebsites() {
return websites;
}
public void setWebsites(String websites) {
this.websites = websites;
}
public String getAccesed() {
return accesed;
}
public void setAccesed(String accesed) {
this.accesed = accesed;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getEdition() {
return edition;
}
public void setEdition(String edition) {
this.edition = edition;
}
public String getInstitution() {
return institution;
}
public void setInstitution(String institution) {
this.institution = institution;
}
public List<String> getEditors() {
return editors;
}
public void setEditors(List<String> editors) {
this.editors = editors;
}
public List<String> getKeywords() {
return keywords;
}
public void setKeywords(List<String> keywords) {
this.keywords = keywords;
}
public String getDoi() {
return doi;
}
public void setDoi(String doi) {
this.doi = doi;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getIssn() {
return issn;
}
public void setIssn(String issn) {
this.issn = issn;
}
}
There is no error from Kundera side. The error is in the Entity class. You have given same Column Name to these two fields.
#Column(name="title")
private List<String> authors = Lists.newArrayList();
#Column(name="title")
private String title;
Update that name & your code will be working fine.
I read a CSV file with university courses (11000 rows) and want to insert this using hibernate into a MySQL database. The problem is that hibernate inserts each row twice. There is a bug regarding this issue. Solution should be to flush each child after persisting.
See here: Hibernate inserts duplicates into a #OneToMany collection and https://hibernate.atlassian.net/browse/HHH-6776
Here is the code from my Spring applications controller:
#RequestMapping(value = "/readcsv")
public String readCSVFile() {
entityManager.setFlushMode(FlushModeType.COMMIT);
//Load all courses and universities and add to hashmap for fast lookup.
ArrayList<Course> allCourses = (ArrayList) entityManager.createQuery("FROM Course").getResultList();
MultiValueMap courseMap = MultiValueMap.decorate(new HashMap<String, Course>());
for (Course c : allCourses) {
courseMap.put(c.getName(), c);
}
ArrayList<University> allUniversities = (ArrayList) entityManager.createQuery("FROM University").getResultList();
HashMap<String, University> universityMap = new HashMap<String, University>();
for (University u : allUniversities) {
universityMap.put(u.getName(), u);
}
Country sweden = (Country) entityManager.createQuery("SELECT c FROM Country c WHERE c.name = 'Sweden'").getSingleResult();
ArrayList<Course> coursesToAdd = new ArrayList<Course>();
//Set fixed parameters for this specific dataset.
String filename = "/Volumes/320gb/macbookpro/Documents/AntagningsstatistikVT2015.csv";
String semester = "Spring2015";
String type = "Classroom";
int pace = 100;
University u;
try {
//Read file
File fileDir = new File(filename);
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(fileDir), "UTF-8"));
String line;
//Loop lines in file
while ((line = in.readLine()) != null) {
// use comma as separator
String[] courseLine = line.split(",");
String name = courseLine[1];
String university = courseLine[2];
//See if the course is already in the database
Collection<Course> coursesWithSameName = courseMap.getCollection(name);
boolean found = false;
if (coursesWithSameName != null) {
for (Course course: coursesWithSameName) {
if (course.getUniversity().getName().equals(university)) {
System.out.println("COURSE ALREADY IN DB : " + name + " " + university);
found = true;
}
}
}
//If not, insert it
if (found == false) {
if (!universityMap.containsKey(university)) {
u = new University();
u.setName(university);
u.setCountry(sweden);
u.setUserAdded(false);
universityMap.put(u.getName(), u);
entityManager.persist(u);
entityManager.flush();
} else {
u = universityMap.get(university);
}
Course course = new Course();
course.setName(name);
course.setUniversity(u);
course.setType(type);
course.setPace(pace);
course.setSemester(semester);
courseMap.put(course.getName(), course);
coursesToAdd.add(course);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("NUMBER OF ROWS IN coursesToAdd : " + coursesToAdd.size()); //Correctly prints 11000
for (Course course : coursesToAdd) { //inserts 22000 rows to db.
entityManager.persist(course);
entityManager.flush();
}
return "redirect:/";
}
Even though I flush after each persist double rows gets inserted. I have the #Transactional annotation on the controller class, is this the reason flush doesn't solve the problem? It however seems much slower when having flush there, which seems like it runs correctly compared to when it does a bulk insert on the end without flushing each insert.
Someone have a clue what is wrong in my code?
Thank you!
Edit:
Added University and Course entities:
Course:
import com.courseportal.project.account.Account;
import com.courseportal.project.utils.AbstractTimestampEntity;
import org.hibernate.annotations.Cascade;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
#Entity
#Table(name="courses")
public class Course extends AbstractTimestampEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private long id;
#Column(name = "code")
private String code;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL)
#OrderBy("date desc")
private List<CourseRank> ranks;
#OneToMany(cascade = CascadeType.ALL)
#OrderBy("date desc")
private List<Comment> comments;
#OneToMany(cascade = CascadeType.ALL)
#OrderBy("date desc")
private List<UserBook> userBooks;
#ElementCollection
private List<CourseBook> courseBooks;
#ManyToMany
#JoinTable(name="courses_enrolledStudents")
private List<Account> enrolledStudents;
#OneToMany(cascade = CascadeType.ALL)
private List<Timeslot> times;
#ManyToOne
private University university;
/*
* fall
* spring
* summer
*/
private String semester;
private String teacherName;
private String courseLink;
private String requirementsLink;
/**
* Undergraduate
* Graduate
*/
private String level;
/**
* Online (MOOC - Massive Open Online Courses)
* Classroom (Traditional)
* Mixed (Lab)
*/
private String type;
/**
* How fast the course going in percentage.
*/
private int pace;
private int numberOfAssignments;
private int numberOfProjects;
private int numberOfExams;
private double credits;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public University getUniversity() {
return university;
}
public void setUniversity(University university) {
this.university = university;
}
public String getCourseLink() {
return courseLink;
}
public void setCourseLink(String courseLink) {
this.courseLink = courseLink;
}
public String getRequirementsLink() {
return requirementsLink;
}
public void setRequirementsLink(String requirementsLink) {
this.requirementsLink = requirementsLink;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public List<Timeslot> getTimes() {
return times;
}
public void setTimes(List<Timeslot> times) {
this.times = times;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getPace() {
return pace;
}
public void setPace(int pace) {
this.pace = pace;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<CourseRank> getRanks() {
return ranks;
}
public void setRanks(List<CourseRank> ranks) {
this.ranks = ranks;
}
public void addRank(CourseRank rank) {
this.ranks.add(rank);
}
public void removeRank(CourseRank rank) {
this.ranks.remove(rank);
}
public void addComment(Comment comment) {
comments.add(comment);
}
//User books, books that are for sale getters and setters
public void removeUserBook(UserBook book) {
this.userBooks.remove(book);
}
public void addUserBook(UserBook book) {
this.userBooks.add(book);
}
public List<UserBook> getUserBooks() {
return userBooks;
}
public void setUserBooks(List<UserBook> userBooks) {
this.userBooks = userBooks;
}
public List<CourseBook> getCourseBooks() {
return courseBooks;
}
public void setCourseBooks(List<CourseBook> courseBooks) {
this.courseBooks = courseBooks;
}
public void removeCourseBook(CourseBook book) {
this.courseBooks.remove(book);
}
public void addCourseBook(CourseBook book) {
this.courseBooks.add(book);
}
public int getNumberOfAssignments() {
return numberOfAssignments;
}
public void setNumberOfAssignments(int numberOfassignments) {
this.numberOfAssignments = numberOfassignments;
}
public int getNumberOfProjects() {
return numberOfProjects;
}
public void setNumberOfProjects(int numberOfprojects) {
this.numberOfProjects = numberOfprojects;
}
public int getNumberOfExams() {
return numberOfExams;
}
public void setNumberOfExams(int numberOfexams) {
this.numberOfExams = numberOfexams;
}
public double getCredits() {
return credits;
}
public void setCredits(double credits) {
this.credits = credits;
}
public List<Account> getEnrolledStudents() {
return enrolledStudents;
}
public void setEnrolledStudents(List<Account> enrolledStudents) {
this.enrolledStudents = enrolledStudents;
}
public void addEnrolledStudent(Account student) {
this.enrolledStudents.add(student);
}
public void removeEnrolledStudent(Account student) {
this.enrolledStudents.remove(student);
}
public String getSemester() {
return semester;
}
public void setSemester(String semester) {
this.semester = semester;
}
}
And University:
import com.courseportal.project.utils.AbstractTimestampEntity;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="universities")
public class University extends AbstractTimestampEntity implements Serializable {
#Id
#GeneratedValue
private int id;
private String name;
#ManyToOne
private Country country;
private boolean userAdded;
public University() {}
public University(String university) {
name = university;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isUserAdded() {
return userAdded;
}
public void setUserAdded(boolean userAdded) {
this.userAdded = userAdded;
}
}