Is second level cache is Session specific in Hibernate - java

I am learning second level caching in hibernate,
this is my entity
package com.hibernate.pojo;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
#Entity
#Table(name = "customer")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
#NamedQuery(query = "select c.customerName from Customer c",name = "findCustomerNames")
public class Customer implements Serializable{
public Customer(){}
public Customer(Integer customerId){
this.customerId = customerId;
}
public Customer(Integer customerId,String customerName){
this.customerId = customerId;
this.customerName = customerName;
}
#Id
private Integer customerId;
private String customerName;
/**
* #return the customerId
*/
public Integer getCustomerId() {
return customerId;
}
/**
* #param customerId the customerId to set
*/
public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}
/**
* #return the customerName
*/
public String getCustomerName() {
return customerName;
}
/**
* #param customerName the customerName to set
*/
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
#Override
public String toString(){
StringBuffer strb = new StringBuffer();
strb.append("\n\n CUSTOMER-ID : ")
.append(this.customerId)
.append("\n CUSTOMER-NAME : ")
.append(this.customerName);
return strb.toString();
}
#Override
public int hashCode(){
return this.customerId * 29;
}
#Override
public boolean equals(Object object){
boolean flag = false;
if(object instanceof Customer){
Customer c = (Customer) object;
flag = (this.customerId == c.getCustomerId()) ? true : false;
}
return flag;
}
}
This is my hibernate 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">org.apache.derby.jdbc.ClientDriver</property>
<property name="hibernate.connection.url">jdbc:derby://localhost:1527/sun-appserv-samples</property>
<property name="hibernate.connection.username">app</property>
<property name="hibernate.connection.password">app</property>
<property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<mapping class="com.hibernate.pojo.Customer" />
</session-factory>
</hibernate-configuration>
The code below is where my question lies
private static void getCustomer() throws Exception{
Session session = HibernateUtil.getSessionFactory().openSession();
Customer obj = null;
obj = (Customer)session.get(Customer.class, new Integer(2));
session.close();
session = HibernateUtil.getSessionFactory().openSession();
obj = (Customer)session.get(Customer.class, new Integer(2));
session.close();
session = HibernateUtil.getSessionFactory().openSession();
obj = (Customer)session.get(Customer.class, new Integer(2));
session.close();
System.out.println(obj);
}
From the code above you can see, i am opening the session thrice and close it thrice.
the query printed in the log is as follows
Hibernate:
select
customer0_.customerId as customerId0_0_,
customer0_.customerName as customer2_0_0_
from
customer customer0_
where
customer0_.customerId=?
in the logs the query is printed only once,
but when i use the below code
private static void getCustomerFromSession() throws Exception{
Session [] session = new Session[]{
HibernateUtil.getSessionFactory().openSession(),
HibernateUtil.getSessionFactory().openSession(),
HibernateUtil.getSessionFactory().openSession()
};
Customer obj1 = (Customer) session[0].get(Customer.class, new Integer(2));
Customer obj2 = (Customer) session[1].get(Customer.class, new Integer(2));
Customer obj3 = (Customer) session[2].get(Customer.class, new Integer(2));
session[0].close();
session[1].close();
session[2].close();
}
i expect here too that the query should be printed once, but the logs print
Hibernate:
select
customer0_.customerId as customerId0_0_,
customer0_.customerName as customer2_0_0_
from
customer customer0_
where
customer0_.customerId=?
Hibernate:
select
customer0_.customerId as customerId0_0_,
customer0_.customerName as customer2_0_0_
from
customer customer0_
where
customer0_.customerId=?
Hibernate:
select
customer0_.customerId as customerId0_0_,
customer0_.customerName as customer2_0_0_
from
customer customer0_
where
customer0_.customerId=?
but the query is printed thrice.
So is my second level cache configuration correct ?
Is second level cache a session specific ?
What changes i should do to my code so that even if i create 3 session, the first Customer obtained from 'get' from first session should be shared by the next two session.
so no printing for 2 select query for the same customer as its present in second level cache.

Actual queries are executed when you commit the transaction or when session is closed. As you did not close the sessions individually, each get method is executed as it is treated 3 different objects to be loaded. If close the session after each get method, then 2nd level cache is looked up and it will be retrieved for next get method. So try closing the session after each get method.

Related

How to update only one attribute of Database using Hibernate... Since it assigns NULL values due to getters and setters?

I am trying to update a row by using its primary key, the issue is that Hibernate updates entire row and since I have not passed values for any other attributes (For Ex : Attributes are empid, name salary and address. I will pass empid=1 and name to be updated. But it will set NULL to other 2 values i.e. address and salary) it assigns NULL to them. I want to Update only selective attributes;
I tried using saveOrUpdate but that too is either entering new or updating same row with NULL values. Is there any other solutions???
Edit :
The below code are written in "Java Project" and not "Maven Project".
The files "MainExecute.java" and "employee.java" are in package "Lab3"
The files "employee.hbm.xml" and "hibernate.cfg.xml" are in the "src" Folder of the same Project.
Here are the codes
MainExecute.java
package Lab3;
import java.util.*;
import org.hibernate.*;
import org.hibernate.cfg.*;
public class MainExecute {
SessionFactory sc = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
public void insert(int empid,String name,int salary,String address) {
Session session = sc.openSession();
Transaction t = session.beginTransaction();
employee e1=new employee();
e1.setEmpid(empid);
e1.setName(name);
e1.setSalary(salary);
e1.setAddress(address);
session.save(e1);
t.commit();
System.out.print("Entered Succesfully");
}
public void update(int empid,String name) {
Session session = sc.openSession();
Transaction t = session.beginTransaction();
Query q = session.createQuery("from employee");
List<?> l = q.getResultList();
Iterator<?> it = l.iterator();
employee e1 = (employee) it.next();
String Address;
int Salary;
//Saved the attributes that exist so that i can bypass the NULL assignment
Salary=e1.getSalary();
Address=e1.getAddress().toString();
//Detached the object from the session else it creates error,
//since hibernate cannot push parallel transaction on same reference objects
session.evict(e1);
employee e2=new employee();
//Setting the attributes that you want to update and rest with already backed up values from attribute
e2.setEmpid(empid);
e2.setName(name);
e2.setAddress(Address);
e2.setSalary(Salary);;
session.saveOrUpdate(e2);
t.commit();
}
public void delete(int empid) {
Session session = sc.openSession();
Transaction t = session.beginTransaction();
employee e1=new employee();
e1.setEmpid(empid);
session.delete(e1);
t.commit();
}
public void display() {
Session session = sc.openSession();
Transaction t = session.beginTransaction();
Query q = session.createQuery("from employee");
List<?> l = q.getResultList();
Iterator<?> it = l.iterator();
if(!it.hasNext()) {
System.out.println("\n\nNo Employees!!!\n");
}
while (it.hasNext()) {
employee e1 = (employee) it.next();
System.out.println("\nEmp ID :"+e1.getEmpid()+
"\t\tName :"+e1.getName()+
"\nSalary :"+e1.getSalary()+
"\t\tAddress :"+e1.getAddress());
}
t.commit();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
MainExecute m1=new MainExecute();
Scanner sc=new Scanner(System.in);
int empid,salary,ch=0;
String name,address;
while(true) {
System.out.println("\n\n1.Insert\t2.Update\n3.Delete\t4.Display\nPress 0 to exit\n");
ch=sc.nextInt();
if(ch==1) {
System.out.println("Emp ID :");
empid=sc.nextInt();
System.out.println("Name :");
name=sc.next();
System.out.println("Salary :");
salary=sc.nextInt();
System.out.println("Address :");
address=sc.next();
m1.insert(empid, name, salary, address);
}else
if(ch==2) {
System.out.println("Emp ID :");
empid=sc.nextInt();
System.out.println("Name :");
name=sc.next();
m1.update(empid, name);
}else
if(ch==3) {
System.out.println("Emp ID :");
empid=sc.nextInt();
m1.delete(empid);
}else
if(ch==4) {
m1.display();
}else
if(ch==0) {
break;
}
}
}
}
employee.java
package Lab3;
//Persistence Class
import javax.persistence.*;
#Entity
#Table(name="employee")
public class employee {
#Id
int empid;
int salary;
String name,address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getEmpid() {
return empid;
}
public void setEmpid(int empid) {
this.empid = empid;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
employee.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
<class name="Lab3.employee" table="employee">
<id name="empid" type="int" column="empid"></id>
<property name="name" type="string" column="name" />
<property name="salary" type="int" column="salary" />
<property name="address" type="string" column="address" />
</class>
</hibernate-mapping>
and hibernate.cfg.xml
<?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.password">1506</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/java</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<mapping class="Lab3.employee"/>
<mapping resource="employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
If you can use hibernate, why don't you can use JPA?
var entity = repo.getById( id );
entity.setValue( value );
repo.save(); // or repo.saveAndFlush();
I figured the following works. The code below is the update method in my execution file which is called.
public void update(int empid,String name) {
Session session = sc.openSession();
Transaction t = session.beginTransaction();
Query q = session.createQuery("from employee");
List<?> l = q.getResultList();
Iterator<?> it = l.iterator();
employee e1 = (employee) it.next();
String Address;
int Salary;
Salary=e1.getSalary();
Address=e1.getAddress().toString();
session.evict(e1);
employee e2=new employee();
e2.setEmpid(empid);
e2.setName(name);
e2.setAddress(Address);
e2.setSalary(Salary);;
session.saveOrUpdate(e2);
t.commit();
}
Try use the native sql to update
Session session = sessionFactory.openSession();
Transaction t = session.beginTransaction();
Query query = session.createQuery("update employee e set e.name = 'newvalue' where e = 1");
query.executeUpdate();
t.commit();
I agree with Jan Tibar said that Jpa is more convenient than hibernate

org.hibernate.QueryException: Unable to resolve path, unexpected token [trying to use left join]

I've created 2 entity classes:
package entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "fr")
public class FR {
#Id
#Column(name = "id")
private String id;
#Column(name = "pid")
private String pId;
#Column(name = "pname")
private String pName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getpId() {
return pId;
}
public void setpId(String pId) {
this.pId = pId;
}
public String getpName() {
return pName;
}
public void setpName(String pName) {
this.pName = pName;
}
}
and
package entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "ar")
public class AR {
#Id
#Column(name = "id")
private String id;
#Column(name = "value1")
private String value1;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
}
and I'm trying to join these tables to fetch the record.
Query qry = session.createQuery("from FR left join AR on FR.pId = AR.id where FR.id=123 or FR.pId=123");
but getting an exception:
org.hibernate.QueryException: Unable to resolve path [FR.id], unexpected token [FR] [from entities.FR left join AR on FR.pId = AR.id where FR.id=123 or FR.pId=123]
and when I'm removing FR from the query
Query qry = session.createQuery("from FR left join AR on FR.pId = AR.id where id=123 or pId=123");
getting another exception:
org.hibernate.hql.internal.ast.QuerySyntaxException: Path expected for join! [from entities.FR left join AR on FR.pId = AR.id where id=123 or pId=123]
I'm in a learning stage of Hibernate and don't know what to do now.
If you've any other info regarding Left Join or the other Joins then please share that too.
hibernate.cfg.xml
<?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.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/examples?zeroDateTimeBehavior=convertToNull</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">Root#123</property>
<property name="hibernate.show_sql">true</property>
<mapping class="entities.FR"/>
<mapping class="entities.AR"/>
</session-factory>
</hibernate-configuration>
Main Class
package hibernate.joins;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class HibernateJoins {
public static void main(String[] args) {
SessionFactory sessionFactory = getSessionFactory();
Session session = sessionFactory.openSession();
Query qry = session.createQuery("from FR left join AR on FR.pId = AR.id and ( FR.id=123 or FR.pId=123 )");
List list = qry.list();
list.forEach(System.out::println);
session.close();
sessionFactory.close();
}
public static SessionFactory getSessionFactory () {
SessionFactory sessionFactory = new Configuration().configure("configurations/hibernate.cfg.xml").buildSessionFactory();
return sessionFactory;
}
}
Since you are using ON clause in your query, therefore, you can not to use where clause separately. Just keep on adding the condition using AND or OR clause(whichever is applicable)

Hibernate could not determine type for: java.util.Collection in many to many relation

I am learning manytomany relationship in hibernate from the tutorial. My example project has two tables called product_table and order_table. I was using many to many relationship between these two tables.
While executing my code I found the following error in the console:
Exception in thread "main" org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: product_details, for columns: [org.hibernate.mapping.Column(orders)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:456)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:423)
at org.hibernate.mapping.Property.isValid(Property.java:226)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:597)
at org.hibernate.mapping.RootClass.validate(RootClass.java:265)
at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:329)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:459)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:710)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:726)
at com.hibernatetest.main.MainApp.hibernateSession(MainApp.java:98)
at com.hibernatetest.main.MainApp.main(MainApp.java:93)
Here's my Hibernate configuration file:
<!-- ~ Hibernate, Relational Persistence for Idiomatic Java ~ ~ License:
GNU Lesser General Public License (LGPL), version 2.1 or later. ~ See the
lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. -->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- In case of using MySQL greater than 5 use MYSQL5 Dialect in stead of mysqldialect -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- Assume test is the database name -->
<property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_test?createDatabaseIfNotExist=true</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create</property>
<mapping class="com.hibernatetest.dto.ProductDetails" />
<mapping class="com.hibernatetest.dto.OrderDetails" />
</session-factory>
</hibernate-configuration>
Here's my OrderDetails classes:
package com.hibernatetest.dto;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
#Entity
#Table(name = "product_details")
public class ProductDetails {
private int productId;
private String productName;
#ManyToMany(mappedBy="product_details")
private Collection<OrderDetails> orders=new ArrayList();
public ProductDetails() {
}
public ProductDetails(String productName) {
this.productName = productName;
}
#Id
#Column(name = "product_id")
#GeneratedValue(strategy = GenerationType.AUTO)
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
#Column(name = "product_name")
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Collection<OrderDetails> getOrders() {
return orders;
}
public void setOrders(Collection<OrderDetails> orders) {
this.orders = orders;
}
}
Here is my OrderDetails class:
package com.hibernatetest.dto;
import java.util.ArrayList;
import java.util.Collection;
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.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "order_details")
public class OrderDetails {
private int orderId;
private String orderName;
#ManyToMany
private Collection<ProductDetails> products = new ArrayList();
public OrderDetails() {
super();
}
public OrderDetails(String orderName) {
super();
this.orderName = orderName;
}
#Id
#Column(name = "order_id")
#GeneratedValue(strategy = GenerationType.AUTO)
public int getOrderId() {
return orderId;
}
public void setOrderId(int orderId) {
this.orderId = orderId;
}
#Column(name = "order_name")
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Collection<ProductDetails> getProduct() {
return products;
}
public void setProduct(Collection<ProductDetails> products) {
this.products = products;
}
}
Here is MainApp class:
package com.hibernatetest.main;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.hibernatetest.dto.Address;
import com.hibernatetest.dto.Office;
import com.hibernatetest.dto.OrderDetails;
import com.hibernatetest.dto.ProductDetails;
import com.hibernatetest.dto.UserDetails;
public class MainApp {
public static void main(String[] args) {
/*
* UserDetails user = new UserDetails(); UserDetails user2=new UserDetails();
* Address address1=new Address("test street1", "test city1", "test state",
* "0000"); Address address2=new Address("test street2", "test city2",
* "test state", "0001"); //user.setUserId(2); user.setUsername("Test User 1");
* user2.setUsername("Test User 2"); user.setJoinedDate(new Date());
* user2.setJoinedDate(new Date()); user.setHomeAddress(address1);
* user.setOfficeAddress(address2); user2.setHomeAddress(address2);
* user2.setOfficeAddress(address1); user.setDescription("test data 1");
* user2.setDescription("test data 2"); user.setJoinedTime(new Date());
* user2.setJoinedTime(new Date());
*
* String officePhone1="00000000"; String officePhone2="00000001"; String
* officePhone3="00000002"; Collection<String> phoneNumbers=new
* ArrayList<String>(); phoneNumbers.add(officePhone1);
* phoneNumbers.add(officePhone2); phoneNumbers.add(officePhone3); Office
* office=new Office(1,"Test Office 1", address1,phoneNumbers);
*
* SessionFactory sessionFactory = new
* Configuration().configure().buildSessionFactory();
*
* Session session = sessionFactory.openSession();
*
* session.beginTransaction();
*
* session.save(user); session.save(user2); session.save(office);
*
* session.getTransaction().commit();
*
* session.close();
*
* user=null;
*
* session= sessionFactory.openSession(); session.beginTransaction();
* user=session.get(UserDetails.class,2);
*
* System.out.println(user.getUserId()+" "+user.getDescription());
*
* session.close(); office=null; session=sessionFactory.openSession();
* session.beginTransaction(); office=session.get(Office.class, 1);
* System.out.println(office.getOfficeName()); session.close();
* System.out.println(office.getPhoneList().size());
*/
ProductDetails product1 = new ProductDetails("Sample product 1");
ProductDetails product2 = new ProductDetails("Sample product 2");
ProductDetails product3 = new ProductDetails("Sample product 3");
ProductDetails product4 = new ProductDetails("Sample product 4");
OrderDetails order1 = new OrderDetails("Order No 1");
OrderDetails order2 = new OrderDetails("Order No 2");
product1.getOrders().add(order1);
product1.getOrders().add(order2);
product2.getOrders().add(order2);
order1.getProduct().add(product1);
order1.getProduct().add(product2);
order1.getProduct().add(product3);
order2.getProduct().add(product1);
order2.getProduct().add(product3);
order2.getProduct().add(product4);
List<Object> insetableObjects = new ArrayList<Object>();
insetableObjects.add(product1);
insetableObjects.add(product2);
insetableObjects.add(product3);
insetableObjects.add(product4);
insetableObjects.add(order1);
insetableObjects.add(order2);
hibernateSession(insetableObjects);
}
public static void hibernateSession(List<Object> collection) {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
for (Object obj : collection) {
session.save(obj);
System.out.println("Object Added");
}
session.getTransaction().commit();
session.close();
}
}
Please guide me to the next steps and thanks in advance.
See this tutorial and Jack Flamp's comments. In order to establish a ManyToMany relationship, you need a #JoinTable referencing the table you want to use in its specific class, and a reference in the other. For instance, in your case it would be something like:
ProductDetails:
#Entity
#Table(name = "product_details")
public class ProductDetails {
private int productId;
private String productName;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(
name = "order_product",
joinColumns = { #JoinColumn(name = "productId") },
inverseJoinColumns = { #JoinColumn(name = "orderId") }
)
private Collection<OrderDetails> orders = new ArrayList();
[...]
OrderDetails:
#Entity
#Table(name = "order_details")
public class OrderDetails {
private int orderId;
private String orderName;
#ManyToMany(mappedBy = "orders")
private Collection<ProductDetails> products = new ArrayList();
Here, your "owning side" (= the one holding the information) is the product. Your product can have multiple orders, and an order belongs to multiple products. Of course, feel free to revert them as you wish if it does not suit your needs. The link I gave you explains well what each annotation does.
EDIT: Make sure that (in the example) the order_product table actually exists. Otherwise, it won't work.

Hibernate keeps updating database even when I work with local variables

I encountered an issue, where the items from my database get deleted at a certain point. It seems like Hibernate updates the database when I'm working with local variables.
Here is my hibernate.cfg.xml file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
" http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- MySQL Configuration -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">dbname</property>
<property name="connection.username">dbusername</property>
<property name="connection.password">dbpassword</property>
<property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="hibernate.show_sql">true</property>
<mapping class="model.User"/>
<mapping class="model.Admin"/>
<mapping class="model.Student"/>
<mapping class="model.Teacher"/>
<mapping class="model.Classroom"/>
<mapping class="model.Quiz"/>
<mapping class="model.Task"/>
<mapping class="model.Solution"/>
<mapping class="model.CorrectSolution"/>
<mapping class="model.WrongSolution"/>
<mapping class="model.Result"/>
</session-factory>
</hibernate-configuration>
I'll post a few examples of code where items get deleted.
This is my own ComboBox class, I save objects of Quiz class in it and I want to remove every Quiz which has an empty TaskList.
private void removeEmptyQuizzes(List<Quiz> quizList){
for(Quiz q : quizList){
if(q.getTaskList().isEmpty()){
quizList.remove(q);
}
}
setItems(FXCollections.observableArrayList(quizList));
}
What happens is that all Quizzes with empty TaskList get completely deleted from the database, not just from the ComboBox.
My application is a Quiz test game, so here's another example. I load the tasks into a List<Task> and then I remove the
private void fillTaskList(){
taskList = SelectedQuiz.getQuiz().getTaskList();
taskNumber = taskList.size();
}
private void loadTask(){
if(!taskList.isEmpty()) {
int taskIndex = new Random().nextInt(taskList.size());
task = taskList.get(taskIndex);
// extra stuff for my quiz - not relevant to the question
/*view.getLbQuestion().setText(task.getQuestion());
List<AnswerBox> answerBoxList = createAnswerBoxList();
List<Solution> solutionList = createSolutionList(task);
int bound = answerBoxList.size();
for(AnswerBox box : answerBoxList){
int index = (new Random().nextInt(bound) + 1) - 1;
Solution sol = solutionList.get(index);
box.setSolution(sol);
solutionList.remove(sol);
bound--;
}*/
taskList.remove(taskList.get(taskIndex));
}
else {
Student student = (Student) LoggedInUtil.getLoggedInUser();
Quiz quiz = SelectedQuiz.getQuiz();
Result result = new Result(correctAnswers, wrongAnswers, student, quiz.getName());
new ResultDao().insertResult(result);
rootView.setEndMiddle(taskNumber, correctAnswers, wrongAnswers);
}
}
Now, I have Tasks saved in the database. However, they all get deleted when I call this new ResultDao().insertResult(result); function. I tried sysouting Quiz.getTaskList.size() in the final else (before saving the Result) and it indeed was 0 and Hibernate updated it.
Now, why does Hibernate automatically update my variables? I have specific Dao classes to work with database, but I don't call them in these cases.
I appreciate all answers, thank you.
EDIT: added InsertResult() method on request
public void insertResult(Result r) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
session.saveOrUpdate(r);
transaction.commit();
}
EDIT2: added mapping for Result class
#Entity
public class Result {
private int result_id, correctAnswers, wrongAnswers;
private Student student;
private SimpleStringProperty quizName = new SimpleStringProperty();
public Result() {
}
public Result(int correctAnswers, int wrongAnswers, Student student, String quizName) {
this.correctAnswers = correctAnswers;
this.wrongAnswers = wrongAnswers;
this.student = student;
this.quizName.set(quizName);
}
#Column(nullable = false)
public int getCorrectAnswers() {
return correctAnswers;
}
public void setCorrectAnswers(int correctAnswers) {
this.correctAnswers = correctAnswers;
}
#Column(nullable = false)
public int getWrongAnswers() {
return wrongAnswers;
}
public void setWrongAnswers(int wrongAnswers) {
this.wrongAnswers = wrongAnswers;
}
#Id
#GenericGenerator(name="id" , strategy="increment")
#GeneratedValue(generator="id")
public int getResult_id() {
return result_id;
}
public void setResult_id(int result_id) {
this.result_id = result_id;
}
#ManyToOne(targetEntity = Student.class)
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
#Column(nullable = false)
public String getQuizName() {
return quizName.get();
}
public SimpleStringProperty quizNameProperty() {
return quizName;
}
public void setQuizName(String quizName) {
this.quizName.set(quizName);
}
#Transient
public SimpleStringProperty studentWithClassProperty(){
String studentWithClass = getStudent().getName() + getStudent().getSurname() + " - " + getStudent().getClassroom().toString();
return new SimpleStringProperty(studentWithClass);
}
}

How to create annotation-based Hibernate mappings?

I am writing a Java project that uses Hibernate ORM and Spring Framework. Right now, when I add a POJO class, I need to modify my hibernate.cfg.xml file, which looks like this:
<?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>
<mapping class="somepackage.class1"/>
<mapping class="somepackage.class2"/>
<!-- etc. -->
</session-factory>
</hibernate-configuration>
Then, I create an annotation-based class. I heard that I could avoid adding per-class mappings in hibernate.cfg.xml if I used proper Hibernate annotations. How can I modify a class to avoid the mappings in an XML file? Here is my example POJO file, generated by NetBeans:
/*
* 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 somepackage.pojo;
import java.io.Serializable;
import java.util.Collection;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
/**
*
* #author D
*/
#Entity
#Table(name = "ACCOUNT")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Account.findAll", query = "SELECT a FROM Account a"),
#NamedQuery(name = "Account.findByLogin", query = "SELECT a FROM Account a WHERE a.login = :login"),
#NamedQuery(name = "Account.findByPassword", query = "SELECT a FROM Account a WHERE a.password = :password")})
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "LOGIN", nullable = false, length = 100)
private String login;
#Size(max = 128)
#Column(name = "PASSWORD", length = 128)
private String password;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
private Collection<Comment> commentCollection;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
private Collection<Article> articleCollection;
public Account() {
}
public Account(String login) {
this.login = login;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#XmlTransient
public Collection<Comment> getCommentCollection() {
return commentCollection;
}
public void setCommentCollection(Collection<Comment> commentCollection) {
this.commentCollection = commentCollection;
}
#XmlTransient
public Collection<Article> getArticleCollection() {
return articleCollection;
}
public void setArticleCollection(Collection<Article> articleCollection) {
this.articleCollection = articleCollection;
}
#Override
public int hashCode() {
int hash = 0;
hash += (login != null ? login.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 Account)) {
return false;
}
Account other = (Account) object;
if ((this.login == null && other.login != null) || (this.login != null && !this.login.equals(other.login))) {
return false;
}
return true;
}
#Override
public String toString() {
return "somepackage.pojo.Account[ login=" + login + " ]";
}
}
I'd suggest you export the hibernate configuration to the spring configuration because of the flexibility that spring provides. Your concern is to not declare the class in the configuration every time you create a new entity. Using spring configuration you can do the following. (packagestoscan property)
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="org.baeldung.spring.persistence.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
Ref: http://www.javacodegeeks.com/2013/05/hibernate-3-with-spring.html

Categories

Resources