I am working on a test project to learn hibernate, unfortunately I am getting this error and have looked at other similar errors, but following them didn't solve my problem. I am still getting this error.
Can someone check what is going wrong, I would really appreciate to know what is my mistake.
The my model classes:
#Entity
#Table(name="survey")
public class Survey implements java.io.Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "survey_id")
private Long _id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "survey")
private List<Question> _questions ;
#Column(name="name")
private String _name;
public Survey() {
super();
}
public Survey(Long id, List<Question> questions, String name) {
super();
_id = id;
_questions = questions;
_name = name;
Assert.notNull(_id, "_id cannot be null");
Assert.notNull(_questions, "_questions cannot be null");
Assert.notNull(_name, "_name cannot be null");
}
public Long getId() {
return _id;
}
public void setId(Long id) {
_id = id;
}
public List<Question> getQuestions() {
return _questions;
}
public void setQuestions(List<Question> questions) {
_questions = questions;
}
public String getName() {
return _name;
}
public void setName(String name) {
_name = name;
}
#Override
public String toString() {
return "Survey [_id=" + _id + ", _questions=" + _questions + ", _name="
+ _name + "]";
}
}
This is the second model class:
#Entity
#Table(name="question")
public class Question implements java.io.Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "id")
private Long _id;
#Column(name = "label")
private String _label;
#Column(name="type")
private QuestionType _type;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="survey_id")
private Survey _survey;
public Question() {
}
public Question(final Long id, final String label, final QuestionType type, final Survey survey,final Long surveyId) {
_id = id;
_label = label;
_type = type;
_survey = survey;
Assert.notNull(_id, "_id cannot be null");
Assert.notNull(_label, "_label cannot be null");
Assert.notNull(_type, "_type cannot be null");
Assert.notNull(_survey, "_survey cannot be null");
}
public Long getId() {
return _id;
}
public void setId(Long id) {
_id = id;
}
public String getLabel() {
return _label;
}
public void setLabel(String label) {
_label = label;
}
public QuestionType getType() {
return _type;
}
public void setType(QuestionType type) {
_type = type;
}
public Survey getSurvey() {
return _survey;
}
public void setSurvey(Survey survey) {
_survey = survey;
}
#Override
public String toString() {
return "Question [_id=" + _id + ", _label=" + _label + ", _type="
+ _type + "]";
}
}
This is my main:
public class Application {
public static void main(String[] args) {
System.out.println("Hibernate one to many (Annotation)");
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Survey survey = new Survey();
survey.setName("Ice Cream final");
session.save(survey);
Question question1 = new Question();
question1.setLabel("Whats your favorite Ice Cream");
question1.setType(QuestionType.TEXT);
question1.setSurvey(survey);
survey.getQuestions().add(question1);
session.save(question1);
session.getTransaction().commit();
System.out.println("Done");
}
This is my hibernate util class:
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
This is my config file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/survey</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping class="xxxxx.Survey" />
<mapping class="xxxxx.Question" />
</session-factory>
Error:
Initial SessionFactory creation failed.org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: xxxx.model.Question.Survey in xxxx.model.Survey._questions
Exception in thread "main" java.lang.ExceptionInInitializerError
at xxxx.util.HibernateUtil.buildSessionFactory(HibernateUtil.java:16)
at xxxx.util.HibernateUtil.<clinit>(HibernateUtil.java:7)
at xxxx.Application.main(Application.java:25)
Caused by: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: xxxx.model.Question.SurveyModel in xxxx.model.Survey._questions
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:655)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:619)
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.buildSessionFactory(Configuration.java:1377)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954)
at xxxx.util.HibernateUtil.buildSessionFactory(HibernateUtil.java:12)
... 2 more
#OneToMany(fetch = FetchType.LAZY, mappedBy = "survey")
private List<Question> _questions ;
So you're telling Hibernate: go look at the Question.survey field to know how this association is mapped.
Is there a field named survey in Question? No there isn't. The field is named _survey.
Please please please, make your code readable and your life easier, and respect the Java naming conventions. Variables don't start with underscores. You really really don't want every JPQL/HQL query of your app to have underscores everywhere.
Mapped By must be getter name of child class.
#OneToMany(fetch = FetchType.LAZY, mappedBy = "survey")
private List<Question> _questions ;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="survey_id")
private Survey survey;
In Question Entity class you must use the same name for field you use in mappedBy in Survey class.So:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "survey")
private List<Question> _questions ;
#JoinColumn(name="survey_id")
private Survey survey;
Related
After starting the program (launching TomCat) there are no tables created in the schema, but the table "player" has to be created automatically.
I checked hibernate config, but can't find where is the problem.
I've tried changing hbm2ddl.auto to hibernate.hbm2ddl.auto (also create, create-drop etc.) but it didn't help.
If there are any ideas, please let me know. Thanks.
Entity class:
package com.game.entity;
import javax.persistence.*;
import java.util.Date;
#Entity
#Table(schema = "rpg", name = "player")
public class Player {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name", length = 12, nullable = false)
private String name;
#Column(name = "title", length = 30, nullable = false)
private String title;
#Column(name = "race", nullable = false)
#Enumerated(EnumType.ORDINAL)
private Race race;
#Column(name = "profession", nullable = false)
#Enumerated(EnumType.ORDINAL)
private Profession profession;
#Column(name = "birthday", nullable = false)
private Date birthday;
#Column(name = "banned", nullable = false)
private Boolean banned;
#Column(name = "level", nullable = false)
private Integer level;
public Player() {
}
public Player(Long id, String name, String title, Race race, Profession profession, Date birthday, Boolean banned, Integer level) {
this.id = id;
this.name = name;
this.title = title;
this.race = race;
this.profession = profession;
this.birthday = birthday;
this.banned = banned;
this.level = level;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Race getRace() {
return race;
}
public void setRace(Race race) {
this.race = race;
}
public Profession getProfession() {
return profession;
}
public void setProfession(Profession profession) {
this.profession = profession;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Boolean getBanned() {
return banned;
}
public void setBanned(Boolean banned) {
this.banned = banned;
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
}
Repository class:
package com.game.repository;
import com.game.entity.Player;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.NativeQuery;
import org.springframework.stereotype.Repository;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Optional;
#Repository(value = "db")
public class PlayerRepositoryDB implements IPlayerRepository {
private final SessionFactory sessionFactory;
public PlayerRepositoryDB() {
Configuration configuration = new Configuration().configure().addAnnotatedClass(Player.class);
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
#Override
public List<Player> getAll(int pageNumber, int pageSize) {
try(Session session = sessionFactory.openSession()){
NativeQuery<Player> nativeQuery = session.createNativeQuery("SELECT * FROM rpg.player", Player.class);
nativeQuery.setFirstResult(pageNumber * pageSize);
nativeQuery.setMaxResults(pageSize);
return nativeQuery.list();
}
}
Hibernate configuration:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://localhost:3306/rpg</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="connection.password">1234</property>
<property name="hbm2ddl.auto">update</property>
<property name="dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="show_sql">true</property>
<property name="hibernate.current_session_context_class">thread</property>
</session-factory>
</hibernate-configuration>
Full project code with pom.xml is available by link:
https://github.com/gamlethot/project-hibernate-1
1-Hibernate does not recognize your repository. You should not mark repo classes as #Repository because they are not interfaces and in your example they are working like a service. So they can be #Service.
2-Do not implement IPlayerRepository. Mark it as #Repository and just autowire it to your service classes (or use constructor injection and just use like a variable)
Like:
#Service
public class PlayerRepositoryDB {
private IPlayerRepository playerRepository;
public PlayerRepositoryDB (IPlayerRepository playerRepository){ //CONSTRUCTOR
this.playerRepository = playerRepository;...
3- DB repository classes are implementing IPlayerRepository but it must be marked as #Repository and It should extend either CrudRepository or JpaRepository (which extends CrudRepository already).
Like:
#Repository
public interface IPlayerRepository extends JpaRepository<Player, Long> {
//Here are the methods;
}
Here, the Long is the type of primary key of Player class.
Hibernate XML:
<property name="hibernate.connection.CharSet">utf8mb4</property>
<property name="hibernate.connection.characterEncoding">UTF-8</property>
<property name="hibernate.connection.useUnicode">true</property>
Connection url:
db.url=jdbc:mysql://localhost:3306/db_name?useUnicode=true&character_set_server=utf8mb4
As a side note I would like to make one clarification that UTF-8 is the character encoding while utf8mb4 is a character set that MySQL supports. MySQL's utf8mb4 is a superset to MySQL's utf8.
Spring/Hibernate filter:
<form accept-charset="UTF-8">
Problem solved.
It was because of javax.persistence.; import instead of
jakarta.persistence. in entity class.
In the code below if I don't clear current session, just the number of girls is returned from the method even if I want to return number of all children of this parent.
It's clearly seen that parent with id 1 has three children (2 girls and 1 boy), but just the girls are returned because of the previous retrieve method which returns parents with girls only. When I clear the session to avoid returning from cache, it returns 3 as expected. Can anybody help me understand why it is like this and how can I avoid this without clearing current session?
#Service
public class ExampleServiceImpl implements ExampleService {
#Autowired
private ExampleRepository exampleRepository;
#Autowired
private SessionFactory sessionFactory;
#Override
#Transactional(readOnly = true)
public int getNumberOfChildren() {
List<Parent> parentList = exampleRepository.retrieveParentsWithGirls();
//sessionFactory.getCurrentSession().clear();
Parent parent = exampleRepository.retrieveParentWithId(1);
System.out.println(parent.getChildSet().size());
return parent.getChildSet().size();
}
}
Let me share all the code I have as well as database scripts to make it more clear.
Repository:
#Repository
public class ExampleRepositoryImpl implements ExampleRepository {
#Autowired
private SessionFactory sessionFactory;
#Override
public List<Parent> retrieveParentsWithGirls() {
CriteriaBuilder builder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Parent> criteria = builder.createQuery(Parent.class);
Root<Parent> parentRoot = criteria.from(Parent.class);
Fetch<Parent, Child> fetchChildren = parentRoot.fetch("childSet", JoinType.LEFT);
Join<Parent, Child> joinChildren = (Join<Parent, Child>) fetchChildren;
criteria.where(builder.equal(joinChildren.get("sex"), "girl"));
criteria.distinct(true);
return sessionFactory.getCurrentSession().createQuery(criteria).getResultList();
}
#Override
public Parent retrieveParentWithId(int id) {
CriteriaBuilder builder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Parent> criteria = builder.createQuery(Parent.class);
Root<Parent> parentRoot = criteria.from(Parent.class);
parentRoot.fetch("childSet", JoinType.LEFT);
criteria.where(builder.equal(parentRoot.get("id"), id));
return sessionFactory.getCurrentSession().createQuery(criteria).getSingleResult();
}
}
Entities:
#Entity
#Table(name = "child")
public class Child {
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name = "sex")
private String sex;
#JoinColumn(name = "parent_id", referencedColumnName = "id")
#ManyToOne(fetch = FetchType.LAZY)
private Parent parent;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
#Entity
#Table(name = "parent")
public class Parent {
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
private Set<Child> childSet;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<Child> getChildSet() {
return childSet;
}
public void setChildSet(Set<Child> childSet) {
this.childSet = childSet;
}
}
DatabaseConfiguration:
#EnableTransactionManagement
#Configuration
#Conditional(DatabaseRequiredCondition.class)
public class DatabaseConfiguration {
#Value("${jdbc.driverClassName}")
private String DB_DRIVER;
#Value("${jdbc.pwd}")
private String DB_PASSWORD;
#Value("${jdbc.url}")
private String DB_URL;
#Value("${jdbc.username}")
private String DB_USERNAME;
#Value("${hibernate.dialect}")
private String HIBERNATE_DIALECT;
#Value("${hibernate.showSql}")
private String HIBERNATE_SHOW_SQL;
#Value("${hibernate.packagesScan}")
private String ENTITYMANAGER_PACKAGES_TO_SCAN;
#Value("${hibernate.tx_timeout}")
private Integer TIMEOUT_AS_SECONDS;
#Bean
#Primary
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
return dataSource;
}
#Bean
#Primary
public LocalSessionFactoryBean sessionFactory() throws IOException {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
hibernateProperties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
hibernateProperties.put("hibernate.format_sql", true);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
#Bean(name="transactionManager")
#Primary
public HibernateTransactionManager transactionManager() throws IOException {
HibernateTransactionManager transactionManager =
new HibernateTransactionManager(sessionFactory().getObject());
transactionManager.setDefaultTimeout(TIMEOUT_AS_SECONDS);
return transactionManager;
}
}
Scripts:
create table parent (id serial);
create table child (id serial, parent_id integer not null, sex character varying(10));
INSERT INTO public.parent values(default);
INSERT INTO public.parent values(default);
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'girl');
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'girl');
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'boy');
Generated Scripts When I run the code:
Hibernate:
select
parent0_.id as id1_23_0_,
childset1_.id as id1_5_1_,
childset1_.parent_id as parent_i3_5_1_,
childset1_.sex as sex2_5_1_,
childset1_.parent_id as parent_i3_5_0__,
childset1_.id as id1_5_0__
from
parent parent0_
left outer join
child childset1_
on parent0_.id=childset1_.parent_id
where
childset1_.sex=?
Hibernate:
select
parent0_.id as id1_23_0_,
childset1_.id as id1_5_1_,
childset1_.parent_id as parent_i3_5_1_,
childset1_.sex as sex2_5_1_,
childset1_.parent_id as parent_i3_5_0__,
childset1_.id as id1_5_0__
from
parent parent0_
left outer join
child childset1_
on parent0_.id=childset1_.parent_id
where
parent0_.id=1
Hibernate version: 5.4.5.Final
I have some tables :
PROFIL : id_profil, ...
EXPERIENCE : id_experience, id_profil#, ...
COMPETENCE_LEVEL : id_competence_level, level, ...
One PROFIL can have lot of EXPERIENCE and lot of COMPETENCE_LEVEL.
One EXPERIENCE can have lot of COMPETENCE_LEVEL.
One COMPETENCE_LEVEL concerns lot of EXPERIENCE.
So, for me, between EXPERIENCE and COMPETENCE_LEVEL, this is a (n-p) ManyToMany relation.
I tried:
PROFIL.java:
#Entity
#Table(name="profil")
public class Profil {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_profil")
private Long idProfil;
public Profil() {
super();
}
public Long getIdProfil() {
return idProfil;
}
public void setIdProfil(Long idProfil) {
this.idProfil = idProfil;
}
#Override
public String toString() {
//[...]
}
}
EXPERIENCE.java:
#Entity
#Table(name="experience")
public class Experience {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_experience")
private Long idExperience;
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
private List<CompetenceLevel> competenceLevels;
public Experience() {
super();
idProfil = new Profil();
}
public Long getIdExperience() {
return idExperience;
}
public void setIdExperience(Long idExperience) {
this.idExperience = idExperience;
}
public Profil getIdProfil() {
return idProfil;
}
public void setIdProfil(Profil idProfil) {
this.idProfil = idProfil;
}
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "experience_competence_level", joinColumns = #JoinColumn(name = "id_experience", referencedColumnName = "id_experience"), inverseJoinColumns = #JoinColumn(name = "id_competence_level", referencedColumnName = "id_competence_level"))
public List<CompetenceLevel> getCompetenceLevels() {
return competenceLevels;
}
public void setCompetenceLevels(List<CompetenceLevel> competenceLevels) {
this.competenceLevels = competenceLevels;
}
#Override
public String toString() {
// [...]
}
}
COMPETENCE_LEVEL.java:
#Entity
#Table(name="competence_level")
public class CompetenceLevel {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id_competence_level")
private Long idCompetenceLevel;
#OneToOne
#JoinColumn(name="id_level")
private Level level;
#OneToOne
#JoinColumn(name="id_profil")
private Profil profil;
private List<Experience> experiences;
public CompetenceLevel() {
super();
}
public Long getIdCompetenceLevel() {
return idCompetenceLevel;
}
public void setIdCompetenceLevel(Long idCompetenceLevel) {
this.idCompetenceLevel = idCompetenceLevel;
}
public Level getLevel() {
return level;
}
public void setLevel(Level level) {
this.level = level;
}
public Profil getProfil() {
return profil;
}
public void setProfil(Profil profil) {
this.profil = profil;
}
#ManyToMany(mappedBy = "competenceLevels")
public List<Experience> getExperiences() {
return experiences;
}
public void setExperiences(List<Experience> experiences) {
this.experiences = experiences;
}
#Override
public String toString() {
// [...]
}
}
So, I have this error :
org.hibernate.MappingException: Could not determine type for: java.util.List, at table: competence_level, for columns: [org.hibernate.mapping.Column(experiences)]
I don't understand why. I follow this tuto : https://hellokoding.com/jpa-many-to-many-relationship-mapping-example-with-spring-boot-maven-and-mysql/
Do you have an idea ? Thanks.
The reason is simply: don't mix field and method annotations in the same persistent class.
Hibernate generates an unclear error here. It is very hard to figure out the reason of the error, if you don't face it before.
In your code, you are mixing field access and property access. See this answer.
I would prefer using only one of the possibilities. I use field annotations, like you did for idProfil.
In the book "Professional Java for Web Applications" by Nicholas S. Williams (very, very good) I found this:
You should never mix JPA property annotations and JPA field
annotations in the same entity. Doing so results in unspecified
behaviour and is very likely to cause errors.
And just for clearness, I wouldn't write this
#ManyToOne
#JoinColumn(name="id_profil")
private Profil idProfil;
// better:
// private Profil profil;
I'm working with Spring, hibernate and MySql but I have some problem with seralization of query result.
First in my entity I added #JsonManagedReference on Set structure (#OneToMany side) and #JsonBackReference on single object reference (#ManyToOne side) and it works but I wasn't be able to retrieve all needed information (for example #ManyToOne reference).
So i swapping #JsonBackReference on set structure and #JsonManagedReference on single object but I retrieve
No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: com.model.tablesField.TableUI["data"]->java.util.ArrayList[0]->com.domain.Car["carType"]->com.domain.CarType_$$_jvst744_f["handler"])
I tried also with #JsonIgnore on Set structure but it doesn't work for the same issues.
This is my spring configuration
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
// properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
properties.put("hibernate.enable_lazy_load_no_trans",true);
return properties;
and this is part of one of my several entities:
/**
* Car generated by hbm2java
*/
#Entity
#Table(name = "car", catalog = "ATS")
public class Car implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer idCar;
#JsonManagedReference
private CarType carType;
#JsonManagedReference
private Fleet fleet;
private String id;
private int initialKm;
private String carChassis;
private String note;
#JsonBackReference
private Set<Acquisition> acquisitions = new HashSet<Acquisition>(0);
public Car() {
}
public Car(CarType carType, Fleet fleet, int initialKm, String carChassis) {
this.carType = carType;
this.fleet = fleet;
this.initialKm = initialKm;
this.carChassis = carChassis;
}
public Car(CarType carType, Fleet fleet, String id, int initialKm, String carChassis, String note,
Set<Acquisition> acquisitions) {
this.carType = carType;
this.fleet = fleet;
this.id = id;
this.initialKm = initialKm;
this.carChassis = carChassis;
this.note = note;
this.acquisitions = acquisitions;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id_car", unique = true, nullable = false)
public Integer getIdCar() {
return this.idCar;
}
public void setIdCar(Integer idCar) {
this.idCar = idCar;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_carType", nullable = false)
public CarType getCarType() {
return this.carType;
}
public void setCarType(CarType carType) {
this.carType = carType;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_fleet", nullable = false)
public Fleet getFleet() {
return this.fleet;
}
public void setFleet(Fleet fleet) {
this.fleet = fleet;
}
#Column(name = "id", length = 5)
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
#Column(name = "initialKm", nullable = false)
public int getInitialKm() {
return this.initialKm;
}
public void setInitialKm(int initialKm) {
this.initialKm = initialKm;
}
#Column(name = "carChassis", nullable = false, length = 20)
public String getCarChassis() {
return this.carChassis;
}
public void setCarChassis(String carChassis) {
this.carChassis = carChassis;
}
#Column(name = "note", length = 100)
public String getNote() {
return this.note;
}
public void setNote(String note) {
this.note = note;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "car")
public Set<Acquisition> getAcquisitions() {
return this.acquisitions;
}
public void setAcquisitions(Set<Acquisition> acquisitions) {
this.acquisitions = acquisitions;
}
}
one method that uses the query:
#Override
#RequestMapping(value = { "/cars/{idFleet}"}, method = RequestMethod.GET)
public #ResponseBody TableUI getCars(#PathVariable int idFleet) {
TableUI ajaxCall=new TableUI();
try {
ajaxCall.setData(fleetAndCarService.findCarsByIdFleet(idFleet));
return ajaxCall;
} catch (QueryException e) {
ErrorResponse errorResponse= ErrorResponseBuilder.buildErrorResponse(e);
LOG.error("Threw exception in FleetAndCarControllerImpl::addCar :" + errorResponse.getStacktrace());
return ajaxCall;
}
}
two class for the query:
public interface DefRdiRepository extends JpaRepository<DefRdi, Integer>{
//#Query("SELECT CASE WHEN COUNT(c) > 0 THEN true ELSE false END FROM DefRdi c WHERE c.parName = ?1 AND c.description= ?2")
//Boolean existsByParNameAndDescription(String parName, String description);
//Query method of spring, I put findBy and then the key of research
DefRdi findByParNameAndDescription(String parName, String description);
}
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
Where is my error? I don't want Set object but only the single reference. The problem is only when I serialize. Thanks
UPDATE:
I use #JSonIgnore on all set collectionts and Eager instead lazy ad all works fine, but is there a way to retrieve all the information only when I want, for example having two different query?
So it doesn't work
#Override
#Transactional
public List<Car> findByFleetIdFleet(int idFleet) {
List<Car> carList= carRepository.findByFleetIdFleet(idFleet);
for (Car car:carList){
Hibernate.initialize(car.getCarType());
Hibernate.initialize(car.getFleet());
}
return carList;
// return carRepository.findByFleetIdFleet(idFleet);
}
All collections need to be fetched eagerly when loading them from data base, in order to get serialized by Spring. Make sure you fetch them eagerly (e.g. FetchMode.JOIN). You could also swap #JsonManagedReference from wanted fields with #JsonIgnore to black listed fields, Spring automatically serialises every field without annotation.
Update:
Changing the data repository to something like that should work, I am not sure it compiles, but I think you will get the point:
#EntityGraph(value = "some.entity.graph", type = EntityGraph.EntityGraphType.FETCH)
#Query(
value = "SELECT c FROM Car c INNER JOIN FETCH c.acquisitions WHERE c.id = :idFleet"
)
public interface CarRepository extends JpaRepository<Car, Integer>, CarRepositoryCustom {
//Query method of spring, I put findBy and then the key of research
List<Car> findByFleetIdFleet(int idFleet);
}
For more information look at this post and read the official documentation.
Workaround:
There seems to be a workaround, however fetching those collections eager like shown above should have a positive performance impact, since there is no need for loading proxies afterwards. Also no open transactions are needed at controller level.
I create this hql in my project (an snack bar), to search all orders that have the product selected by the user as parameter:
select order from Order order, OrderItem item
inner join order.cod_order_item as item
inner join item.cod_product as cod_product
where cod_product = id
However, when I run the createQuery(), gives a nullpointer at org.hibernate.hql.ast.HqlSqlWalker.createFromJoinElement.
What am i doing wrong?
Below, here's my codes:
OrderDAO.java
public class OrderDAO {
private Session session;
public PedidoDAO(Session session){
this.session = session;
}
public List<Order> getAllOrderFromProduct(Product product{
String hql = "select order from Order order, OrderItem item " +
"inner join order.order_item_id as item " +
"inner join item.product_id as product_id " +
"where product_id = '"+ product.getId() + "'";
Configuration cfg = new Configuration();
SessionFactory factory = cfg.configure().buildSessionFactory();
Session session = factory.openSession();
Query query = session.createQuery(hql);
List result = query.list();
return result;
}
}
Order.java (entity)
#Entity
public class Order{
#Id
#GeneratedValue
private Long order_id;
#Column(name="order_date", nullable=false, length=15)
private Date data;
#Column(name="order_total", nullable=false, length=8)
private double total;
/* Relacionamentos */
#Column(name="employee_id", nullable=false, length=8)
private Long employee_id;
#Column(name="customer_id", nullable=false, length=8)
private Long customer_id;
#Column(name="order_item_id", nullable=false, length=8)
private Long order_item_id;
public Long getId() {
return order_id;
}
public void setId(Long order_id) {
this.order_id= order_id;
}
public Date getOrderDate() {
return order_date;
}
public void setOrderDate(Date order_date) {
this.order_date = order_date;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public Long getFuncionario() {
return cod_funcionario;
}
public void setEmployee(Long employee_id) {
this.employee_id= employee_id;
}
public Long getCustomer() {
return customer_id;
}
public void setCustomer(Long customer_id) {
this.customer_id= customer_id;
}
public Long getOrderItem() {
return order_item_id;
}
public void setOrderItem(Long order_item_id) {
this.order_item_id= order_item_id;
}
}
My hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://localhost:3306/lanchonete_db</property>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- this will show us all sql statements -->
<property name="hibernate.show_sql">true</property>
<!-- mapping files -->
<mapping class="gigabyte.bean.Customer" />
<mapping class="gigabyte.bean.Address"/>
<mapping class="gigabyte.bean.Employee" />
<mapping class="gigabyte.bean.Order"/>
<mapping class="gigabyte.bean.OrderItem" />
<mapping class="gigabyte.bean.Product"/>
<mapping class="gigabyte.bean.Phone" />
</session-factory>
</hibernate-configuration>
Any help is welcome.
I found my error! I forgot to reference the annotation #ManyToMany in relationship table on Order.java, then the Hibernate tried to get the relationship between the two tables and found nothing. Now, works fine with this query, based on #axtavt answer:
select order from Order order, OrderItem item
inner join order.order_item as item
where item.cod_product = id
My Order.java corrected:
#Entity
public class Order{
#Id
#GeneratedValue
private Long order_id;
#Column(name="order_date", nullable=false, length=15)
private Date data;
#Column(name="order_total", nullable=false, length=8)
private double total;
/* Relationships*/
#Column(name="employee_id", nullable=false, length=8)
private Long employee_id;
#Column(name="customer_id", nullable=false, length=8)
private Long customer_id;
#ManyToMany(targetEntity=OrderItem.class, fetch=FetchType.LAZY)
#Fetch(FetchMode.SUBSELECT)
#JoinTable(name = "order_order_item", joinColumns = { #JoinColumn(name = "cod_order") },
inverseJoinColumns = { #JoinColumn(name = "cod_item") })
public Set<OrderItem> setOrderItem = new HashSet<OrderItem>();
public Long getId() {
return order_id;
}
public void setId(Long order_id) {
this.order_id= order_id;
}
public Date getOrderDate() {
return order_date;
}
public void setOrderDate(Date order_date) {
this.order_date = order_date;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public Long getFuncionario() {
return cod_funcionario;
}
public void setEmployee(Long employee_id) {
this.employee_id= employee_id;
}
public Long getCustomer() {
return customer_id;
}
public void setCustomer(Long customer_id) {
this.customer_id= customer_id;
}
public Set<OrderItem> getOrderItem() {
return orderItem;
}
public void setOrderItem(Set<OrderItem> orderItem) {
this.orderItem= orderItem;
}
}
You certainly don't need to add OrderItem to from explicitly since it's already added by join:
select order from Order order
inner join order.cod_order_item as item
inner join item.cod_product as cod_product
where cod_product = id