Unable to update a record via Hibernate - java

I am able to successfully create and insert entries in a table via Hibernate, however for some reason my update method appears to not be working.
For my table, I chose to use Java annotations in the POJO file to create it.
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
*
* #author
*/
#Entity
#Table(name="student") //name of DB table that will be created via Hibernate
public class Student {
#Id //Primary Key
#Column(name = "id") //map to column
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "marks")
private Integer marks;
public Student(Integer id, String name, Integer marks) {
this.id = id;
this.name = name;
this.marks = marks;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getMarks(){
return marks;
}
public void setMarks(Integer marks) {
this.marks = marks;
}
#Override
public String toString() {
return "Student: " + this.getId() + " | " + this.getName() + " | " + this.getMarks();
}
}
As aforementioned, the table is successfully created in a MySQL database. However, I am unable to update an objects Marks (grade) via my HQL query:
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
*
* #author
*/
public class HibernateModuleTen {
private static SessionFactory factory = new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Student.class)
.buildSessionFactory();
public static void main(String[] args) {
Session newSession = factory.getCurrentSession();
try {
/*Create Student Objects
in Memory
*/
Student student1 = new Student(100, "Greg", 95);
Student student2 = new Student(101, "Mary", 91);
Student student3 = new Student(102, "Sidi", 90);
Student student4 = new Student(103, "Rokia", 92);
Student student5 = new Student(104, "Abdel", 88);
Student student6 = new Student(105, "Christine", 77);
Student student7 = new Student(106, "Hamma", 90);
Student student8 = new Student(107, "Ahmadu", 68);
Student student9 = new Student(108, "Halimatu", 96);
Student student10 = new Student(109, "Iziren", 99);
//Begin transaction
newSession.beginTransaction();
//Save all the students
newSession.save(student1);
newSession.save(student2);
newSession.save(student3);
newSession.save(student4);
newSession.save(student5);
newSession.save(student6);
newSession.save(student7);
newSession.save(student8);
newSession.save(student9);
newSession.save(student10);
newSession.getTransaction().commit();
//Update a Student Record
updateStudent(107, 34);
//Delete a record if marks are less than 35 and then update Database
deleteStudent();
//Print all records
newSession = factory.openSession();
newSession.beginTransaction();
Criteria newCriteria = newSession.createCriteria(Student.class);
List<Student> students = newSession.createQuery("from Student").list(); //.list is .getResultList in later versions of Hibernate
for (Student aStudent : students) {
System.out.println(aStudent.toString());
}
newSession.getTransaction().commit();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
factory.close();
}
}
public static void updateStudent(Integer id, Integer marks) throws HibernateException {
/*Update Transaction*/
Session newSession = factory.openSession();
newSession.beginTransaction();
Student studentToUpdate = (Student)newSession.get(Student.class, id); //Choose record 107 to update
//Update the marks of Student based on ID and marks
studentToUpdate.setMarks(marks);
newSession.update(studentToUpdate);
//Commit to the Transaction
newSession.getTransaction().commit();
newSession.close();
}
public static void deleteStudent() throws HibernateException {
Session newSession = factory.openSession();
newSession.beginTransaction();
newSession.createQuery("delete from student s where smarks < 35")
.executeUpdate(); //Used for updates and deletes
newSession.getTransaction().commit();
newSession.close();
}
}
The update method effectively takes one of the records in the table via the id column and updates the element in the marks column.

There was an issue with my delete method:
public static void deleteStudent() throws HibernateException {
Session newSession = factory.openSession();
newSession.beginTransaction();
newSession.createQuery("delete from student s where smarks < 35")
.executeUpdate(); //Used for updates and deletes
newSession.getTransaction().commit();
newSession.close();
}
If one looks closely at the query, the "delete from student" should be "delete from Student" with a capital s. Careless error.

You didn't post your errors here, but looks like your Student bean class doesn't have a default constructor which is being invoked while executing
Student studentToUpdate = (Student)newSession.get(Student.class, id);
You can try after adding a default constructor to Student class along with your custom constructor.

Related

Hibernate mapping exception even though mappings appear correct

I've this Java application in package com.luv2code.hibernate.demo:
package com.luv2code.hibernate.demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.luv2code.hibernate.demo.entity.Employee;
public class CreateEmployeeDemo {
public static void main(String[] args) {
// create session factory
SessionFactory factory = new Configuration()
.configure("hibernate.cfg.xml")
.addAnnotatedClass(Employee.class)
.buildSessionFactory();
// create a session
Session session = factory.getCurrentSession();
try {
// create the employee object
System.out.println("Creating a new employee object...");
Employee tempEmployee = new Employee("John", "Doe", "Doe Corp.");
// start a transaction
session.beginTransaction();
// save the employee object
System.out.println("Saving the employee...");
session.save(tempEmployee);
// commit the transaction
session.getTransaction().commit();
// find the employee's ID: primary key
System.out.println("Save employee. Generated ID: " + tempEmployee.getId());
// now get a new session and start transaction
session = factory.getCurrentSession();
session.beginTransaction();
// retrieve employee based on the ID: primary key
System.out.println("\nGettin employee with id: " + tempEmployee.getId());
Employee myEmployee = session.get(Employee.class, tempEmployee.getId());
System.out.println("Get complete: " + myEmployee);
// commit the transaction
session.getTransaction().commit();
// delete student id=2
System.out.println("Deleting student id=2");
session.createQuery("delete from Student where id = '2'").executeUpdate();
// commit the transaction
session.getTransaction().commit();
System.out.println("Done!");
}
finally {
factory.close();
}
}
}
It uses this Employee class in package com.luv2code.hibernate.demo.entity:
package com.luv2code.hibernate.demo.entity;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
#Column(name="company")
private String company;
public Employee() {
}
public Employee(String firstName, String lastName, String company) {
this.firstName = firstName;
this.lastName = lastName;
this.company = company;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
#Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", company=" + company + "]";
}
}
When I run the program I get this error:
Saving the employee...
Jul 17, 2020 6:46:40 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:mysql://localhost:3306/hb_student_tracker?useSSL=false&serverTimezone=UTC]
Jul 17, 2020 6:46:40 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections close
ERROR: Connection leak detected: there are 1 unclosed connections upon shutting down pool jdbc:mysql://localhost:3306/hb_student_tracker?useSSL=false&serverTimezone=UTC
Exception in thread "main" org.hibernate.MappingException: Unknown entity: com.luv2code.hibernate.demo.entity.Employee
at org.hibernate.metamodel.internal.MetamodelImpl.entityPersister(MetamodelImpl.java:704)
at org.hibernate.internal.SessionImpl.getEntityPersister(SessionImpl.java:1606)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:114)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:194)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:179)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:75)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:634)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:627)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:622)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:351)
at com.sun.proxy.$Proxy25.save(Unknown Source)
at com.luv2code.hibernate.demo.CreateEmployeeDemo.main(CreateEmployeeDemo.java:33)
I can't see what could be wrong here. It seems to be a mapping exception but I think my mappings should be correct. Can anybody spot the issue?
Use #Entity and #Table for map database table name with Employee class
#Entity
#Table(name = "employee")
public class Employee { ... }

Stackoverflow error occuring when converting Object list to Json string

I have a Java RESTapi, where I want to convert a list of my custom Pet object into Json, and display it in an endpoint.
This I what I have so far:
#Path("/allPets")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() {
List<Pet> petList = new ArrayList<>();
petList.addAll(facade.returnAllPets());
String json = gson.toJson(petList);
//TODO return proper representation object
return Response.ok().entity(json).build();
}
I'm using the facade pattern where I have a method of adding Java entities to a list as such:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PetHospitaljpa");
public Collection<Pet> returnAllPets (){
EntityManager em = emf.createEntityManager();
//vi laver en typed query for at specificere hvilken datatype,
// det er vi leder efter, i dette tilfælde er det en Pet
TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
return query.getResultList();
}
I'm returning a collection in case I want to change the data structure of ArrayList to something else later.
I have tried several workarounds, but I keep getting a stack overflow error.
Iøm aware of the fact, that I need to use DTO's instead, and I have made a custom method to change entities to DTO's as such:
public static DTOPet converttoDTO(Pet entity){
DTOPet dto = new DTOPet();
dto.setId(entity.getId());
dto.setName(entity.getName());
dto.setBirth(entity.getBirth());
dto.setDeath(entity.getDeath());
dto.setSpecies(entity.getSpecies());
return dto;
}
I'm not sure if this is good code practice if I there is something else I can do instead to transform a collection of entities into DTO's?
As pointed out. The problem occurs because I have a circular reference.
inside my Pet Entity class:
#ManyToOne
private Owner ownerId;
inside my Owner Entity class:
#OneToMany(mappedBy = "ownerId")
private Collection<Pet> petCollection;
My Pet Class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package Entities;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
/**
*
* #author kristoffer
*/
#Entity
#Table(name = "pet")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Pet.findAll", query = "SELECT p FROM Pet p")
, #NamedQuery(name = "Pet.findById", query = "SELECT p FROM Pet p WHERE p.id = :id")
, #NamedQuery(name = "Pet.findByName", query = "SELECT p FROM Pet p WHERE p.name = :name")
, #NamedQuery(name = "Pet.findByBirth", query = "SELECT p FROM Pet p WHERE p.birth = :birth")
, #NamedQuery(name = "Pet.findBySpecies", query = "SELECT p FROM Pet p WHERE p.species = :species")
, #NamedQuery(name = "Pet.findByDeath", query = "SELECT p FROM Pet p WHERE p.death = :death")})
public class Pet implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 45)
#Column(name = "name")
private String name;
#Basic(optional = false)
#NotNull
#Column(name = "birth")
#Temporal(TemporalType.DATE)
private Date birth;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 45)
#Column(name = "species")
private String species;
#Column(name = "death")
#Temporal(TemporalType.DATE)
private Date death;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "petId")
private Collection<Event> eventCollection;
#JoinColumn(name = "owner_id", referencedColumnName = "id")
#ManyToOne
private Owner ownerId;
public Pet() {
}
public Pet(Integer id) {
this.id = id;
}
public Pet(Integer id, String name, Date birth, String species) {
this.id = id;
this.name = name;
this.birth = birth;
this.species = species;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public String getSpecies() {
return species;
}
public void setSpecies(String species) {
this.species = species;
}
public Date getDeath() {
return death;
}
public void setDeath(Date death) {
this.death = death;
}
#XmlTransient
public Collection<Event> getEventCollection() {
return eventCollection;
}
public void setEventCollection(Collection<Event> eventCollection) {
this.eventCollection = eventCollection;
}
public Owner getOwnerId() {
return ownerId;
}
public void setOwnerId(Owner ownerId) {
this.ownerId = ownerId;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Pet)) {
return false;
}
Pet other = (Pet) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "Pet{" + "id=" + id + ", name=" + name + ", birth=" + birth + ", species=" + species + ", death=" + death + ", eventCollection=" + eventCollection + ", ownerId=" + ownerId + '}';
}
}
EDIT:
I tried creating a method, where I convert all the objects to DTO's, but the string is still empty when it is displayed:
#Path("/allPets")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() {
//med denne metode skal vi bruge et DTO(data transfer object til at formatere til Json)
List<Pet> petList = new ArrayList<>();
List<DTOPet> DTOPetList = new ArrayList<>();
petList.addAll(facade.returnAllPets());
for(Pet pet: petList){
DTOPet dtopet = EntitytoDTO.converttoDTO(pet);
DTOPetList.add(dtopet);
}
String json = gson2.toJson(DTOPetList);
return Response.ok().entity(json).build();
}
When I use the debugger, the new list is created successfully, with the right parameters, but the String JSON is just created like this [{},{},{},{}], even though I use GSON
You need to detect what place of error. I recommend to add debug information, like
#Path("/allPets")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getPetsfromCollection() {
log.debug("getPetsfromCollection start");
List<Pet> petList = new ArrayList<>(facade.returnAllPets());
log.debug("petList" + petList.length());
String json = gson.toJson(petList);
log.debug("json " + json);
//TODO return proper representation object
return Response.ok().entity(json).build();
}
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PetHospitaljpa");
public Collection<Pet> returnAllPets (){
log.debug("returnAllPets start");
EntityManager em = emf.createEntityManager();
log.debug("createNamedQuery start");
TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
log.debug("single result" + query.getSingleResult() );
TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
log.debug("list result" + query.getResultList());
TypedQuery<Pet> query = em.createNamedQuery("Pet.findAll", Pet.class);
return query.getResultList();
}
P.S. Also, please show Pet class, may be problem is with this class.
Update: I recommend also to try temporary delete:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "petId")
private Collection<Event> eventCollection;
And / or
#JoinColumn(name = "owner_id", referencedColumnName = "id")
#ManyToOne
private Owner ownerId;
And check do you have such SO exception or not. It is look like Event or Owner table is too big or have circle dependencies.
Without seeing what the "Pet" class looks like, it is difficult to pinpoint the problem. I suspect you have a variable of another class in your Pet class that also has a reference to the pet class itself (creating a circular reference that would cause a stack overflow in the serialization process)

TypeMisMatchException in hibernate

Following is my Person class:
package com.subir.sample;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
#Entity
#Table(name ="person",uniqueConstraints = {#UniqueConstraint(columnNames= {"NAME"})})
public class Person implements Serializable{
/**
*
*/
private static final long serialVersionUID = -2728179031744032393L;
int age;
String name;
char isVip;
public Person() {
}
public Person(int age, String name, char isVip) {
this.age = age;
this.name = name;
this.isVip = isVip;
}
#Id
#Column(name="AGE")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Id
#Column(name="NAME")
//#OneToMany(mappedBy="NAME")
private Set <Subject> subjects;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Id
#Column(name="ISVIP")
public char getIsVip() {
return isVip;
}
public void setIsVip(char isVip) {
this.isVip = isVip;
}
}
And the following is my class for add and view persons.
package com.subir.sample;
import org.hibernate.Transaction;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class PersonDbAccess {
public static void addPerson(String name, int age, char isVip, Session session, org.hibernate.Transaction tx) {
try {
tx = session.beginTransaction();
Person p = new Person(age, name, isVip);
session.save(p);
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
public static void viewPerson(String name, Session session) {
try {
System.out.println("Name value in view method is :: " + name);
Person person = (Person)session.get(Person.class, name);
System.out.println("Person.class is ::" + Person.class + " Person.class.getName is :: "
+ Person.class.getName() + " Person.class.getSimpleName() is :: " + Person.class.getSimpleName()
+ " Person.class.getCanonicalName is :: " + Person.class.getCanonicalName());
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
}
public static void main(String[] args) {
SessionFactory factory = HibernateUtils.buildSessionFactory();
Session session = factory.openSession();
Transaction tx = null;
String name = "Subir";
int age = 20;
char isVip = 'Y';
// addPerson(name,age,isVip,session,tx);
viewPerson("Subir", session);
}
}
And following is my stacktrace:
Exception in thread "main" org.hibernate.TypeMismatchException: Provided id of the wrong type for class com.subir.sample.Person. Expected: class com.subir.sample.Person, got class java.lang.String
at org.hibernate.event.internal.DefaultLoadEventListener.checkIdClass(DefaultLoadEventListener.java:166)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:86)
at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1240)
at org.hibernate.internal.SessionImpl.access$1900(SessionImpl.java:204)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.doLoad(SessionImpl.java:2842)
at org.hibernate.internal.SessionImpl$IdentifierLoadAccessImpl.load(SessionImpl.java:2816)
at org.hibernate.internal.SessionImpl.get(SessionImpl.java:1076)
at com.subir.sample.PersonDbAccess.main(PersonDbAccess.java:53)
Even though, I am passing object.class,String in the get method of the session object, it is giving me type mismatch exception.
You need to pass the ID to your hibernate session get method. In your case you have a compound key , fetching only by name might result in more than one object being returned which contradicts with the nature of the get operation which returns a single object by primary key.
You need to use a Criteria or Query here.
On another note if you want to use the Session.get method, instead of marking multiple columns with ID which is not JPA complient you should create an EmbededId and use it in the Session.get method. Then it will not incompatible type.
Read https://vladmihalcea.com/the-best-way-to-map-a-composite-primary-key-with-jpa-and-hibernate/
UPDATE:
I can see you have Unique constraint on name. Why do you need the AGE and the isVip to be part of your key , because marking them with ID you are effectivly making them part of your key.

How to save multiple objects via ArrayList in hibernate?

I have a Student entity. My idea is to collect multiple student objects in an ArrayList and save all objects from that list to the database. When do you use #ElementCollection annotation? Does it apply to situations like this?
Student:
package basic;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
public Student() {
}
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;
}
#Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
public Student(String name) {
this.name = name;
}
}
Runner:
package basic;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Runner {
public static void main(String[] args) {
SessionFactory sessionFactory = new Configuration().configure("/basic/hibernate.cfg.xml").buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
List<Student> students = new ArrayList<>();
students.add(new Student("Michael"));
students.add(new Student("Dave"));
students.add(new Student("Tom"));
students.add(new Student("Dinesh"));
students.add(new Student("Lakshman"));
students.add(new Student("Cruise"));
session.save(students);
session.getTransaction().commit();
session.close();
}
}
Error
Exception in thread "main" org.hibernate.MappingException: Unknown entity: java.util.ArrayList
at org.hibernate.metamodel.internal.MetamodelImpl.entityPersister(MetamodelImpl.java:620)
at org.hibernate.internal.SessionImpl.getEntityPersister(SessionImpl.java:1596)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:104)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:668)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:660)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:655)
at basic.Runner.main(Runner.java:27)
You have to do something like this:
for(Student student : students) {
session.save(student);
}
If you want to save entity you should map it. ArrayList<> is not mapped entity. Student has mapping so you should save it separately.
#ElementCollection you should use to define relation between object - here you have nice explenation https://en.wikibooks.org/wiki/Java_Persistence/ElementCollection
To save list of object, you need to iterate by objects, something like this -> How to insert multiple rows into database using hibernate?
I would further recommend to use another Hibernate command to avoid an Out Of Memory error...
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
for (int i = 0 ; i < students.size(); i++) {
session.save(students.get(i));
if (i % 100 == 0) {//a batch size for safety
session.flush();
session.clear();
}
}
transaction.commit();
session.close();
sessionFactory.close();

Firing HQL in ManyToOne relationship

I have College and Student entities having OneToMany relationship:
#Entity
public class College {
#Id
#GeneratedValue
private int collegeId;
private String collegeName;
#OneToMany
private Collection<Student> students = new ArrayList<Student>();
public int getCollegeId() {
return collegeId;
}
public void setCollegeId(int collegeId) {
this.collegeId = collegeId;
}
public String getCollegeName() {
return collegeName;
}
public void setCollegeName(String collegeName) {
this.collegeName = collegeName;
}
public Collection<Student> getStudents() {
return students;
}
public void setStudents(Collection<Student> students) {
this.students = students;
}
}
#Entity
public class Student {
#Id
#GeneratedValue
private int studentId;
private String studentName;
public int getStudentId() {
return studentId;
}
public void setStudentId(int studentId) {
this.studentId = studentId;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
}
There is a foreign key to college in Student table.
If I want to fetch all students from a perticular college then in native SQL I can do tha with following query:
Select * from student where collegeId=1
Is it possible to achieve same with HQL by selecting from students entities and not from college entity.
My utility class:
public class ManyToOne {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.hibernate.examples");
EntityManager em = emf.createEntityManager();
College college1 = new College();
college1.setCollegeName("College1");
College college2 = new College();
college2.setCollegeName("College2");
Student student1 = new Student();
student1.setStudentName("std1");
college1.getStudents().add(student1);
Student student2 = new Student();
student2.setStudentName("std2");
college2.getStudents().add(student2);
Student student3 = new Student();
student3.setStudentName("std3");
college1.getStudents().add(student3);
Student student4 = new Student();
student4.setStudentName("std4");
college1.getStudents().add(student4);
em.getTransaction().begin();
em.persist(college1);
em.persist(college2);
em.persist(student1);
em.persist(student2);
em.persist(student3);
em.persist(student4);
em.getTransaction().commit();
em.close();
em = emf.createEntityManager();
em.getTransaction().begin();
String queryString = "select students from "+ College.class.getName()+" where collegeId = 1";
Query query = em.createQuery(queryString);
List<Student> students = query.getResultList();
for(int i=0;i<students.size();i++)
System.out.println(students.get(i).getStudentName());
em.getTransaction().commit();
em.close();
emf.close();
}
}
Exception stacktrace:
Exception in thread "main" java.lang.IllegalStateException: No data type for node: org.hibernate.hql.internal.ast.tree.IdentNode
\-[IDENT] IdentNode: 'students' {originalText=students}
at org.hibernate.hql.internal.ast.tree.SelectClause.initializeExplicitSelectClause(SelectClause.java:174)
at org.hibernate.hql.internal.ast.HqlSqlWalker.useSelectClause(HqlSqlWalker.java:924)
at org.hibernate.hql.internal.ast.HqlSqlWalker.processQuery(HqlSqlWalker.java:692)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:665)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:301)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:249)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:278)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:206)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:158)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:131)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:93)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:167)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:301)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1800)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:328)
at utils.ManyToOne.main(ManyToOne.java:66)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Try with this (just saw in your other question that mappings are ok)
String queryString = "select s from Student s where s.college.collegeId = 1";
EDIT
With regard to your comment, Hibernate has a "feature" where if it can't find a field with given name, it will just pass down to SQL whatever you give it. In your case it means that
String queryString = "from Student where collegeId=1";
since collegeId is not a field in Student, it will be passed into SQL as it is, resulting in the query you want. Of course, the downside is coupling of your code to underlying DB model, bypassing ORM mappings.

Categories

Resources