I have class Menu, it's a self to self with manytoone and onetomany relational.
package models;
import java.util.*;
import javax.persistence.*;
import play.db.ebean.*;
import play.data.format.*;
import play.data.validation.*;
import static play.data.validation.Constraints.*;
import javax.validation.*;
import org.codehaus.jackson.annotate.JsonBackReference;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonManagedReference;
import com.avaje.ebean.*;
import play.i18n.Messages;
#Entity
public class Menu extends Model {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
#Required
#MinLength(4)
#MaxLength(30)
public String name;
public String url;
#Transient
public boolean hasChild() {
return url.isEmpty();
}
public Integer idx;
#Temporal(TemporalType.TIMESTAMP)
#Formats.DateTime(pattern = "yyyy/MM/dd hh:mm:ss")
public Date created;
#Required
public boolean enabled;
#ManyToOne
#JsonBackReference
public Menu parent;
#OneToMany
#JsonManagedReference("parent")
public List<Menu> children;
public static Model.Finder<Long, Menu> find = new Model.Finder<Long, Menu>(Long.class, Menu.class);
public static List<Menu> findTops() {
return find.where().eq("parent_id", null).eq("enabled", true).orderBy("idx asc").findList();
}
public static List<Menu> findChildsByParent(Menu parent) {
return findChildsByParent(parent, true);
}
public static List<Menu> findChildsByParent(Menu parent, boolean enabled) {
return find.where().eq("parent_id", parent.id).eq("enabled", enabled).orderBy("idx asc").findList();
}
public static boolean hasChilds(Menu parent) {
return hasChilds(parent, true);
}
public static boolean hasChilds(Menu parent, boolean enabled) {
return find.where().eq("parent_id", parent.id).eq("enabled", enabled).findList().size() > 0;
}
public static Page<Menu> findPage(int page, int size) {
return find.findPagingList(size).getPage(page - 1);
}
public Menu() {
}
}
In Controller code is :
#BodyParser.Of(BodyParser.Json.class)
public static Result menuJson() {
if (menus == null) {
menus = Menu.find.all();
}
JsonNode json = new ObjectMapper().valueToTree(menus);
return ok(json);
}
Error details is:
[RuntimeException: java.lang.IllegalArgumentException: Query threw SQLException:Unknown column 't1.menu_id' in 'on clause' Bind values:[1] Query was: select t0.id c0 , t1.id c1, t1.name c2, t1.url c3, t1.idx c4, t1.created c5, t1.enabled c6, t1.parent_id c7 from menu t0 left outer join menu t1 on t1.menu_id = t0.id where t0.id = ? order by t0.id (through reference chain: com.avaje.ebean.common.BeanList[0]->models.Menu["children"])]
It's there have good solution to solve them or how to declare a custom serialize? For the tree model i don't have good object to class design,is't there a better design for this env.?
I solve them.
Add a mapped on OneToMany is works.
package models;
import java.util.*;
import javax.persistence.*;
import play.db.ebean.*;
import play.data.format.*;
import play.data.validation.*;
import static play.data.validation.Constraints.*;
import javax.validation.*;
import org.codehaus.jackson.annotate.JsonBackReference;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonManagedReference;
import com.avaje.ebean.*;
import play.i18n.Messages;
#Entity
public class Menu extends Model {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
#Required
#MinLength(4)
#MaxLength(30)
public String name;
public String url;
#Transient
public boolean hasChild() {
return url.isEmpty();
}
public Integer idx;
#Temporal(TemporalType.TIMESTAMP)
#Formats.DateTime(pattern = "yyyy/MM/dd hh:mm:ss")
public Date created;
#Required
public boolean enabled;
#ManyToOne
#JsonBackReference
public Menu parent;
#OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
#JsonManagedReference
public List<Menu> children;
public static Model.Finder<Long, Menu> find = new Model.Finder<Long, Menu>(Long.class, Menu.class);
public static List<Menu> findTops() {
return find.where().eq("parent_id", null).eq("enabled", true).orderBy("idx asc").findList();
}
public static List<Menu> findChildsByParent(Menu parent) {
return findChildsByParent(parent, true);
}
public static List<Menu> findChildsByParent(Menu parent, boolean enabled) {
return find.where().eq("parent_id", parent.id).eq("enabled", enabled).orderBy("idx asc").findList();
}
public static boolean hasChilds(Menu parent) {
return hasChilds(parent, true);
}
public static boolean hasChilds(Menu parent, boolean enabled) {
return find.where().eq("parent_id", parent.id).eq("enabled", enabled).findList().size() > 0;
}
public static Page<Menu> findPage(int page, int size) {
return find.findPagingList(size).getPage(page - 1);
}
public Menu() {
}
}
Related
I use Quarkus + Hibernate to sync data to the DB and I've noticed during testing that sometimes my entity isn't updated. I've created a minimal example adjusting the original example https://github.com/quarkusio/quarkus-quickstarts/tree/main/hibernate-orm-quickstart
Here are my adjustments:
import.sql
DROP TABLE IF EXISTS fruit CASCADE;
CREATE TABLE fruit (
fruitsSequence INT PRIMARY KEY,
name TEXT NOT NULL,
test INT
);
Fruit.java
package org.acme.hibernate.orm;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.google.common.base.Objects;
#Entity
#Table(name = "known_fruits")
public class Fruit {
#Id
#SequenceGenerator(name = "fruitsSequence", sequenceName = "known_fruits_id_seq", allocationSize = 1, initialValue = 10)
#GeneratedValue(generator = "fruitsSequence")
private Integer id;
#Transient
private String name = "";
#Column(name = "test")
private Integer test = -1;
public Fruit() {
}
public Fruit(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "name")
#Access(AccessType.PROPERTY)
public String getChangedName() {
return "a" + name;
}
public String getName() {
return name;
}
public void setTest(Integer test) {
this.test = test;
}
public Integer getTest() {
return test;
}
#Column(name = "name")
#Access(AccessType.PROPERTY)
protected void setChangedName(String name) {
this.name = name.substring(1);
}
public void setName(String name) {
this.name = name;
}
#Override
public int hashCode() {
return Objects.hashCode(name, test);
}
#Override
public boolean equals(Object o) {
if (o instanceof Fruit) {
Fruit other = (Fruit) o;
return name.equals(other.name) && test.equals(other.test);
}
return false;
}
}
Replaced the test withDBTest.java
package org.acme.hibernate.orm;
import static io.restassured.RestAssured.given;
import static org.junit.jupiter.api.Assertions.assertEquals;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.UserTransaction;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
#QuarkusTest
public class DBTest {
#Inject
EntityManager m_em;
#Inject
UserTransaction m_transaction;
#Test
void testUpdate() throws Exception {
Fruit fruit = given().when().body("{\"name\" : \"Pear\"}").contentType("application/json").post("/fruits")
.then().statusCode(201).extract().as(Fruit.class);
m_transaction.begin();
Fruit db = m_em.find(Fruit.class, fruit.getId());
db.setName("Apple");
db.setTest(13);
m_transaction.commit();
db = m_em.find(Fruit.class, fruit.getId());
assertEquals(13, db.getTest(), "Unexpected test");
assertEquals("Apple", db.getName(), "Unexpected name");
}
#Test
void testUpdateLongName() throws Exception {
Fruit fruit = given().when().body(
"{\"name\" : \"PeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaDBaaaaaaaaaaaaaar\"}")
.contentType("application/json").post("/fruits").then().statusCode(201).extract().as(Fruit.class);
m_transaction.begin();
Fruit db = m_em.find(Fruit.class, fruit.getId());
db.setName(fruit.getName() + "Apple");
db.setTest(13);
m_transaction.commit();
db = m_em.find(Fruit.class, fruit.getId());
assertEquals(13, db.getTest(), "Unexpected test");
assertEquals(fruit.getName() + "Apple", db.getName(), "Unexpected name");
}
#Test
void testUpdateNameOnly() throws Exception {
Fruit fruit = given().when().body("{\"name\" : \"Pear\"}").contentType("application/json").post("/fruits")
.then().statusCode(201).extract().as(Fruit.class);
m_transaction.begin();
Fruit db = m_em.find(Fruit.class, fruit.getId());
db.setName("Apple");
m_transaction.commit();
db = m_em.find(Fruit.class, fruit.getId());
assertEquals(-1, db.getTest(), "Unexpected test");
assertEquals("Apple", db.getName(), "Unexpected name");
}
#Test
void testUpdateNameOnlyREST() throws Exception {
Fruit fruit = given().when().body("{\"name\" : \"Pear\"}").contentType("application/json").post("/fruits")
.then().statusCode(201).extract().as(Fruit.class);
given().when().body("{\"name\" : \"Apple\"}").contentType("application/json").put("/fruits/" + fruit.getId())
.then().statusCode(200).extract().as(Fruit.class);
Fruit db = m_em.find(Fruit.class, fruit.getId());
assertEquals(-1, db.getTest(), "Unexpected test");
assertEquals("Apple", db.getName(), "Unexpected name");
}
}
What I see is that testUpdateNameOnly and testUpdateNameOnlyREST fail whereas the other tests run as expected. In my original testcase, even changing another field didn't update the TEXT field hence the test with the long name. The reason why the name is altered when writing it to the DB is to encrypt it (the outcome is a BASE64 string).
I am not sure if this is a configuration issue or an actual bug.
Thanks for helps in advance!
As suggested by the comments this seems to be a bug (https://github.com/quarkusio/quarkus/issues/16619).
It works with the AttributeConver:
Fruit.java:
package org.acme.hibernate.orm;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import com.google.common.base.Objects;
#Entity
#Table(name = "known_fruits")
public class Fruit {
#Id
#SequenceGenerator(name = "fruitsSequence", sequenceName = "known_fruits_id_seq", allocationSize = 1, initialValue = 10)
#GeneratedValue(generator = "fruitsSequence")
private Integer id;
#Column(name = "name")
#Convert(converter = NameConverter.class)
private String name = "";
#Column(name = "test")
private Integer test = -1;
public Fruit() {
}
public Fruit(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setTest(Integer test) {
this.test = test;
}
public Integer getTest() {
return test;
}
public void setName(String name) {
this.name = name;
}
#Override
public int hashCode() {
return Objects.hashCode(name, test);
}
#Override
public boolean equals(Object o) {
if (o instanceof Fruit) {
Fruit other = (Fruit) o;
return name.equals(other.name) && test.equals(other.test);
}
return false;
}
}
NameConverter.java:
package org.acme.hibernate.orm;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
#Converter
public class NameConverter implements AttributeConverter<String, String> {
#Override
public String convertToDatabaseColumn(String name) {
return "a" + name;
}
#Override
public String convertToEntityAttribute(String name) {
return name.substring(1);
}
}
I've been going on a hobby project of mine for a couple of weeks that is basically a quiz assistant. What it does is after a test, I'm going to check what questions and answers I got right by inputting part of the question text and retrieving the category (e.g.: Chemistry), the questions related to my search queue (e.g.: NaCl, DNA, pH) and the answers related to those questions.
All of them are stored in a MySQL database, in this manner: Database Scheme.
When I first started, I was using an EAGER way of fetching all the records (since there weren't as many as today). However, today I'm counting a large collection of questions and answers and can't seem to get the lazy loading to be working.
Considering the following simple code:
Main.java
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.mybizname.quizassistant.database.dao.impl.CategoryDaoImpl;
import org.mybizname.quizassistant.database.entity.impl.CategoryEntityImpl;
import org.mybizname.quizassistant.database.entity.impl.QuestionEntityImpl;
import org.mybizname.quizassistant.database.utilities.HibernateUtil;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
List<CategoryEntityImpl> categories = new CategoryDaoImpl().fetchAll();
categories.forEach((category) -> {
Set<QuestionEntityImpl> questions = category.getQuestions();
});
HibernateUtil.shutdown();
System.exit(0);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
}
HibernateUtil.java
import java.util.HashMap;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;
import org.mybizname.quizassistant.database.entity.impl.AnswerEntityImpl;
import org.mybizname.quizassistant.database.entity.impl.CategoryEntityImpl;
import org.mybizname.quizassistant.database.entity.impl.QuestionEntityImpl;
public class HibernateUtil {
private static StandardServiceRegistry standardServiceRegistry;
private static SessionFactory sessionFactory;
static {
StandardServiceRegistryBuilder standardServiceRegistryBuilder = new StandardServiceRegistryBuilder();
Map<String, String> hibernateConfiguration = new HashMap<>();
hibernateConfiguration.put(Environment.DIALECT, "org.hibernate.dialect.MySQLDialect");
hibernateConfiguration.put(Environment.DRIVER, "com.mysql.jdbc.Driver");
hibernateConfiguration.put(Environment.URL, "jdbc:mysql://localhost:3306/quiz_assistant");
hibernateConfiguration.put(Environment.USER, "root");
hibernateConfiguration.put(Environment.PASS, "pwd");
hibernateConfiguration.put(Environment.QUERY_TRANSLATOR, "org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory");
hibernateConfiguration.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "org.hibernate.context.internal.ThreadLocalSessionContext");
hibernateConfiguration.put(Environment.SHOW_SQL, "true");
hibernateConfiguration.put(Environment.FORMAT_SQL, "true");
standardServiceRegistryBuilder.applySettings(hibernateConfiguration);
standardServiceRegistry = standardServiceRegistryBuilder.build();
MetadataSources metadataSources = new MetadataSources(standardServiceRegistry);
metadataSources.addAnnotatedClass(CategoryEntityImpl.class);
metadataSources.addAnnotatedClass(QuestionEntityImpl.class);
metadataSources.addAnnotatedClass(AnswerEntityImpl.class);
Metadata metadata = metadataSources.getMetadataBuilder().build();
sessionFactory = metadata.getSessionFactoryBuilder().build();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session openSession() {
return sessionFactory.openSession();
}
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
public static void shutdown() {
if (sessionFactory != null) {
StandardServiceRegistryBuilder.destroy(standardServiceRegistry);
}
}
}
GenericEntity.java
import java.io.Serializable;
import java.util.Date;
public interface GenericEntity extends Serializable {
public Long getId();
public void setId(Long id);
public Date getRegistrationTimestamp();
public void setRegistrationTimestamp(Date registrationTimestamp);
}
AbstractGenericEntity.java
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
public abstract class AbstractGenericEntity implements GenericEntity {
#Override
abstract public Long getId();
#Override
abstract public void setId(Long id);
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "registrationTimestamp", length = 19)
protected Date registrationTimestamp;
#Override
public Date getRegistrationTimestamp() {
return this.registrationTimestamp;
}
#Override
public void setRegistrationTimestamp(Date registrationTimestamp) {
this.registrationTimestamp = registrationTimestamp;
}
}
GenericDao.java
import java.util.List;
public interface GenericDao<T> {
public void persist(T entity);
public void update(T entity);
public void remove(T entity);
public void removeAll();
public List<T> fetchAll();
public List<T> fetchAllByExample(T entity);
public T findById(Long id);
public Class<T> getType();
}
AbstractGenericDao.java
import java.lang.reflect.ParameterizedType;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.mybizname.quizassistant.database.utilities.HibernateUtil;
public abstract class AbstractGenericDao<T> implements GenericDao<T> {
private final Class<T> type;
public AbstractGenericDao() {
type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
#Override
public void persist(T entity) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void update(T entity) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void remove(T entity) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void removeAll() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public List<T> fetchAll() {
List<T> entities;
Session session = HibernateUtil.getCurrentSession();
Transaction transaction = session.beginTransaction();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(getType());
criteriaQuery.from(getType());
entities = session.createQuery(criteriaQuery).getResultList();
transaction.commit();
return entities;
}
#Override
public List<T> fetchAllByExample(T entity) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public T findById(Long id) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public Class<T> getType() {
return type;
}
}
CategoryEntityImpl
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.mybizname.quizassistant.database.entity.AbstractGenericEntity;
#Entity
#Table(name = "category", catalog = "quiz_assistant", uniqueConstraints = #UniqueConstraint(columnNames = "name"))
public class CategoryEntityImpl extends AbstractGenericEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#Column(name = "name", unique = true, nullable = false)
private String name;
#Column(name = "shortDescription")
private String shortDescription;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
private Set<QuestionEntityImpl> questions = new HashSet<>();
#OneToMany(fetch = FetchType.LAZY, mappedBy = "category")
private Set<AnswerEntityImpl> answers = new HashSet<>();
public CategoryEntityImpl() {
}
public CategoryEntityImpl(String name, Date registrationTimestamp) {
this.name = name;
this.registrationTimestamp = registrationTimestamp;
}
public CategoryEntityImpl(String name, String shortDescription, Date registrationTimestamp, Set<QuestionEntityImpl> questions, Set<AnswerEntityImpl> answers) {
this.name = name;
this.shortDescription = shortDescription;
this.registrationTimestamp = registrationTimestamp;
this.questions = questions;
this.answers = answers;
}
#Override
public Long getId() {
return this.id;
}
#Override
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getShortDescription() {
return this.shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
public Set<QuestionEntityImpl> getQuestions() {
return this.questions;
}
public void setQuestions(Set<QuestionEntityImpl> questions) {
this.questions = questions;
}
public Set<AnswerEntityImpl> getAnswers() {
return this.answers;
}
public void setAnswers(Set<AnswerEntityImpl> answers) {
this.answers = answers;
}
}
QuestionEntityImpl
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.mybizname.quizassistant.database.entity.AbstractGenericEntity;
#Entity
#Table(name = "question", catalog = "quiz_assistant")
public class QuestionEntityImpl extends AbstractGenericEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "categoryId", nullable = false)
private CategoryEntityImpl category;
#Column(name = "identifier", nullable = false)
private String identifier;
#Column(name = "text", nullable = false)
private String text;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "question")
private Set<AnswerEntityImpl> answers = new HashSet<>();
public QuestionEntityImpl() {
}
public QuestionEntityImpl(CategoryEntityImpl category, String identifier, String text, Date registrationTimestamp) {
this.category = category;
this.identifier = identifier;
this.text = text;
this.registrationTimestamp = registrationTimestamp;
}
public QuestionEntityImpl(CategoryEntityImpl category, String identifier, String text, Date registrationTimestamp, Set<AnswerEntityImpl> answers) {
this.category = category;
this.identifier = identifier;
this.text = text;
this.registrationTimestamp = registrationTimestamp;
this.answers = answers;
}
#Override
public Long getId() {
return this.id;
}
#Override
public void setId(Long id) {
this.id = id;
}
public CategoryEntityImpl getCategory() {
return this.category;
}
public void setCategory(CategoryEntityImpl category) {
this.category = category;
}
public String getIdentifier() {
return this.identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
public Set<AnswerEntityImpl> getAnswers() {
return this.answers;
}
public void setAnswers(Set<AnswerEntityImpl> answers) {
this.answers = answers;
}
}
AnswerEntityImpl
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.mybizname.quizassistant.database.entity.AbstractGenericEntity;
#Entity
#Table(name = "answer", catalog = "quiz_assistant")
public class AnswerEntityImpl extends AbstractGenericEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "categoryId", nullable = false)
private CategoryEntityImpl category;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "questionId", nullable = false)
private QuestionEntityImpl question;
#Column(name = "identifier", nullable = false)
private String identifier;
#Column(name = "text", nullable = false)
private String text;
public AnswerEntityImpl() {
}
public AnswerEntityImpl(CategoryEntityImpl category, QuestionEntityImpl question, String identifier, String text, Date registrationTimestamp) {
this.category = category;
this.question = question;
this.identifier = identifier;
this.text = text;
this.registrationTimestamp = registrationTimestamp;
}
#Override
public Long getId() {
return this.id;
}
#Override
public void setId(Long id) {
this.id = id;
}
public CategoryEntityImpl getCategory() {
return this.category;
}
public void setCategory(CategoryEntityImpl category) {
this.category = category;
}
public QuestionEntityImpl getQuestion() {
return this.question;
}
public void setQuestion(QuestionEntityImpl question) {
this.question = question;
}
public String getIdentifier() {
return this.identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
}
POM Dependencies:
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.6.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
</dependencies>
There are still CategoryDaoImpl.java, QuestionDaoImpl.java and AnswerDaoImpl.java which are just empty and simply extend AbstractGenericDao.java.
Now, in Main.java, I retrieve the list of categories from the database:
List<CategoryEntityImpl> categories = new CategoryDaoImpl().fetchAll();
And then, when I am trying to loop thru them via:
categories.forEach((category) -> {
Set<QuestionEntityImpl> questions = category.getQuestions();
});
I get the following:
Exception in thread "AWT-EventQueue-0" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: org.mybizname.quizassistant.database.entity.impl.CategoryEntityImpl.questions, could not initialize proxy - no Session
The only workaround I found so far is a long and not so clever looking hack. Instead of the loop from above, I have to do this:
categories.forEach((category) -> {
System.out.println(category.getName());
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
session.lock(category, LockMode.NONE);
Set<QuestionEntityImpl> questions = category.getQuestions();
questions.forEach((question) -> {
System.out.println("\t" + question.getText());
});
tx.commit();
});
I know this kind of questions go far, far back, but trust me that I have tried anything I could find on the web and the above example is the only solution I found that works. Maybe I am mistaken somewhere? I would do that, just that it doesn't seem right to have to rewrite the same piece of code over and over again for every view I have and every time I need to refresh some data.
Some help would be appreciated.
Thank you in advance.
I have 3 tables in my database: Professors, Disciplines and Courses.
From Professors and Disciplines to Courses it is many to one relationship.
I have tried to put foreign keys, but it does not work.
Course class:
package com.licenta.ascourses.model;
import java.io.Serializable;
import javax.persistence.AssociationOverride;
import javax.persistence.AssociationOverrides;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="Courses")
#AssociationOverrides({
#AssociationOverride(name = "pk.discipline",
joinColumns = #JoinColumn(name = "IDDISCIPLINE")),
#AssociationOverride(name = "pk.professor",
joinColumns = #JoinColumn(name = "IDPROFESSOR")) })
public class Course implements Serializable {
private CourseId idCourse=new CourseId();
private int year;
private int semester;
public Course()
{
}
public Course(CourseId idCourse, int idDiscipline, int idProfessor,int year, int semester) {
super();
this.idCourse = idCourse;
this.year = year;
this.semester = semester;
}
#EmbeddedId
public CourseId getIdCourse() {
return idCourse;
}
public void setIdCourse(CourseId idCourse) {
this.idCourse = idCourse;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getSemester() {
return semester;
}
public void setSemester(int semester) {
this.semester = semester;
}
}
CourseId class for composite primary key:
package com.licenta.ascourses.model;
import java.io.Serializable;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
#Embeddable
public class CourseId implements Serializable{
#ManyToOne
#JoinColumn(name="IDDISCIPLINE")
private int idDiscipline;
#ManyToOne
#JoinColumn(name="IDPROFESSOR")
private int idProfessor;
private String courseNo;
public int getIdDiscipline() {
return idDiscipline;
}
public void setIdDiscipline(int idDiscipline) {
this.idDiscipline = idDiscipline;
}
public int getIdProfessor() {
return idProfessor;
}
public void setIdProfessor(int idProfessor) {
this.idProfessor = idProfessor;
}
public String getCourseNo() {
return courseNo;
}
public void setCourseNo(String courseNo) {
this.courseNo = courseNo;
}
public boolean equals(Object o) {
return true;
}
public int hashCode() {
return 1;
}
}
Discipline class:
package com.licenta.ascourses.model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="Disciplines")
public class Discipline implements Serializable {
private int idDiscipline;
#Id
private String name;
private String description;
private int an;
private int semestru;
public Discipline()
{
}
public Discipline(int idDiscipline, String name, String description, int an, int semestru) {
super();
this.idDiscipline = idDiscipline;
this.name = name;
this.description = description;
this.an = an;
this.semestru = semestru;
}
public Discipline(int idDiscipline, String name, String description, int an, int semestru, Set<Course> courses) {
super();
this.idDiscipline = idDiscipline;
this.name = name;
this.description = description;
this.an = an;
this.semestru = semestru;
}
public int getIdDiscipline() {
return idDiscipline;
}
public void setIdDiscipline(int idDiscipline) {
this.idDiscipline = idDiscipline;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getAn() {
return an;
}
public void setAn(int an) {
this.an = an;
}
public int getSemestru() {
return semestru;
}
public void setSemestru(int semestru) {
this.semestru = semestru;
}
}
And this is how my Course table is made by Hibernate:
create table Courses (
courseNo varchar2(255 char) not null,
idDiscipline number(10,0) not null,
idProfessor number(10,0) not null,
semester number(10,0) not null,
year number(10,0) not null,
primary key (courseNo, idDiscipline, idProfessor)
)
So, the foreign keys does not appear. Please help me
Try to change this:
#ManyToOne
#JoinColumn(name="IDDISCIPLINE")
private int idDiscipline;
#ManyToOne
#JoinColumn(name="IDPROFESSOR")
private int idProfessor;
private String courseNo;
to this:
#ManyToOne
#JoinColumn(name="idDiscipline")
private Discipline discipline;
#ManyToOne
#JoinColumn(name="idProfessor")
private Professor professor;
private String courseNo;
Following class fail to load with the Hibernate
package com.project.alice.entities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonProperty;
#Table
#Entity
public class AnyInformation<T, K> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty("id")
private long id;
#JsonProperty("parent")
#ManyToOne
private T parent;
#ManyToOne
#JsonProperty("parentType")
private K parentType;
#JsonProperty("informationType")
private String informationType;
#JsonProperty("information")
private String information;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public T getParent() {
return parent;
}
public void setParent(T parent) {
this.parent = parent;
}
public K getParentType() {
return parentType;
}
public void setParentType(K parentType) {
this.parentType = parentType;
}
public String getInformationType() {
return informationType;
}
public void setInformationType(String informationType) {
this.informationType = informationType;
}
public String getInformation() {
return information;
}
public void setInformation(String information) {
this.information = information;
}
}
org.hibernate.AnnotationException:
Property com.project.alice.entities.AnyInformation.parent
has an unbound type and no explicit target entity.
Resolve this Generic usage issue or set an explicit target attribute
(eg #OneToMany(target=) or use an explicit #Type
Please help me here.
You should try something like -
#ManyToOne(targetEntity=Sample.class)
#JoinColumn(name = "<ID>")
private P parent;
#OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST, targetEntity=Sample.class)
private List<C> children;
Where, P and C extends Sample Class.
I hope it helps.
Note : As per my knowledge It can't be generic as you are expecting. You can not provide any object as a parameter. But the object should be related to the entity you are defining like Parent or Child. That's how it works in Hibernate.
I have a problem that Hibernate is unable to determine the type for Collection at the table Region. I am trying to create a foreign key of table Actels through one-to-many relationship. a region can have many actels.
In detail:
The error I am getting is this:
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: Region, for columns: [org.hibernate.mapping.Column(collection_actels)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:316)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:294)
at org.hibernate.mapping.Property.isValid(Property.java:238)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:469)
at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1294)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1742)
at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:94)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:905)
... 20 more
Region.java:
package com.springJPA.domain;
import java.io.Serializable;
import java.lang.String;
import java.util.Collection;
import javax.persistence.*;
import com.springJPA.domain.Actels;
/**
* Entity implementation class for Entity: Reseau
*
*/
#Entity
public class Region implements Serializable {
private int id_region;
private String region;
private String ville;
private int codep;
private int num_region;
private int num_ville;
private Collection<Actels> collection_actels;
private static final long serialVersionUID = 1L;
private Collection<Actels> actels;
public Region() {
super();
}
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "id_Sequence_region")
#SequenceGenerator(name = "id_Sequence_region", sequenceName = "ID_SEQ_REGION")
public int getId_region() {
return id_region;
}
public void setId_region(int id_region) {
this.id_region = id_region;
}
public String getRegion() {
return this.region;
}
public void setRegion(String region) {
this.region = region;
}
public String getVille() {
return this.ville;
}
public void setVille(String ville) {
this.ville = ville;
}
public int getCodep() {
return this.codep;
}
public void setCodep(int codep) {
this.codep = codep;
}
public Collection<Actels> getCollection_actels() {
return collection_actels;
}
public void setCollection_actels(Collection<Actels> collection_actels) {
this.collection_actels = collection_actels;
}
public int getNum_region() {
return num_region;
}
public void setNum_region(int num_region) {
this.num_region = num_region;
}
public int getNum_ville() {
return num_ville;
}
public void setNum_ville(int num_ville) {
this.num_ville = num_ville;
}
#OneToMany
#JoinColumn(name = "Region_id_region", referencedColumnName = "id_region")
public Collection<Actels> getActels() {
return actels;
}
public void setActels(Collection<Actels> param) {
this.actels = param;
}
}
Actels.java:
package com.springJPA.domain;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
/**
* Entity implementation class for Entity: Actels
*
*/
#Entity
public class Actels implements Serializable {
private int id_actels;
private String nomActels;
private int num_actel;
private Region region;
private static final long serialVersionUID = 1L;
public Actels() {
super();
}
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "id_Sequence_actels")
#SequenceGenerator(name = "id_Sequence_actels", sequenceName = "ID_SEQ_ACTELS")
public int getId_actels() {
return id_actels;
}
public void setId_actels(int id_actels) {
this.id_actels = id_actels;
}
public String getNomActels() {
return this.nomActels;
}
public void setNomActels(String nomActels) {
this.nomActels = nomActels;
}
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
public int getNum_actel() {
return num_actel;
}
public void setNum_actel(int num_actel) {
this.num_actel = num_actel;
}
}
Put any JPA annotation above each field instead of getter property:
#SequenceGenerator(name = "id_Sequence_actels", sequenceName = "ID_SEQ_ACTELS")
private int id_actels;
And:
#JoinColumn(name = "Region_id_region", referencedColumnName = "id_region")
private Collection<Actels> actels;
#Column
#ElementCollection(targetClass=String.class)
public Set<String> getOptions() {
return options;
}
OR
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "....")
public Set<String> getOptions() {
return options;
}