Today I did some experiments with hibernate.
First of all there is no deeper sense behind my program. I just wanted to try the framework.
I planed the following db tables:
Car (Auto)
Driver (Fahrer)
Wohnung (Flat)
Guest (Fahrgast)
with the following bidirectional mappings:
driver – flat onetoone
driver – car onetomany
car – guest manytomany
After preparing the single classes I wrote my worker to insert some demodata. Up to this point everything works as expected.
Finally I would like to remove one of my drivers. But hibernate tells me, that it would be re-saved by a certain guest. Unfortunately I don’t understand why.
I expected everything to be fine after removing the driver from the driver collection of the corresponding cars.
class car
package mycode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="auto")
public class Auto {
#Id #GeneratedValue
private int id;
#Column(name="nummernschild", nullable = false)
private String nummernschild;
#OneToMany(cascade=CascadeType.ALL, mappedBy="auto")
private List<Fahrer>fahrers = new ArrayList<Fahrer>();
#ManyToMany(cascade=CascadeType.ALL)
private List<Fahrgast>fahrgasts = new ArrayList<Fahrgast>();
public List<Fahrgast> getFahrgasts() {
return fahrgasts;
}
public void setFahrgasts(List<Fahrgast> fahrgasts) {
this.fahrgasts = fahrgasts;
}
public List<Fahrer> getFahrers() {
return fahrers;
}
public void setFahrers(List<Fahrer> fahrers) {
this.fahrers = fahrers;
}
private LocalDate kaufdatum;
public LocalDate getKaufdatum() {
return kaufdatum;
}
public void setKaufdatum(LocalDate kaufdatum) {
this.kaufdatum = kaufdatum;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNummernschild() {
return nummernschild;
}
public void setNummernschild(String nummernschild) {
this.nummernschild = nummernschild;
}
}
class driver
package mycode;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name="fahrer")
public class Fahrer {
#Id #GeneratedValue()
private int id;
private String vorname, nachname;
private int alter;
#OneToOne (cascade=CascadeType.ALL)
#JoinColumn(name="id")
private Wohnung wohnung;
#ManyToOne(cascade=CascadeType.ALL)
private Auto auto;
public Auto getAuto() {
return auto;
}
public void setAuto(Auto auto) {
this.auto = auto;
}
public Wohnung getWohnung() {
return wohnung;
}
public void setWohnung(Wohnung wohnung) {
this.wohnung = wohnung;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getVorname() {
return vorname;
}
public void setVorname(String vorname) {
this.vorname = vorname;
}
public String getNachname() {
return nachname;
}
public void setNachname(String nachname) {
this.nachname = nachname;
}
public int getAlter() {
return alter;
}
public void setAlter(int alter) {
this.alter = alter;
}
}
class flat
package mycode;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
#Entity
#Table(name="wohnung")
public class Wohnung {
#Id #GeneratedValue(generator = "newGenerator")
#GenericGenerator(name="newGenerator", strategy="foreign" , parameters= {#Parameter(value="fahrer", name="property")})
private int id;
#Column(nullable=false)
private String ort, straße;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="id")
private Fahrer fahrer;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getOrt() {
return ort;
}
public void setOrt(String ort) {
this.ort = ort;
}
public String getStraße() {
return straße;
}
public void setStraße(String straße) {
this.straße = straße;
}
public Fahrer getFahrer() {
return fahrer;
}
public void setFahrer(Fahrer fahrer) {
this.fahrer = fahrer;
}
}
class guest
package mycode;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
#Entity
#Table(name="fahrgast")
public class Fahrgast {
#Id #GeneratedValue
private int id;
#Column(nullable=false)
private int kundennummmer;
private String vornname, nachname;
#ManyToMany(mappedBy="fahrgasts")
private List<Auto>autos = new ArrayList<Auto>();
public List<Auto> getAutos() {
return autos;
}
public void setAutos(List<Auto> autos) {
this.autos = autos;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getKundennummmer() {
return kundennummmer;
}
public void setKundennummmer(int kundennummmer) {
this.kundennummmer = kundennummmer;
}
public String getVornname() {
return vornname;
}
public void setVornname(String vornname) {
this.vornname = vornname;
}
public String getNachname() {
return nachname;
}
public void setNachname(String nachname) {
this.nachname = nachname;
}
}
class worker
package mycode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class Worker {
private Session session;
private SessionFactory sf;
public static void main(String[] args) {
Worker worker = new Worker();
worker.work();
}
private void init()
{
Configuration configuration = new Configuration().configure();
sf = configuration.buildSessionFactory();
session = sf.openSession();
}
private void work()
{
init();
Auto auto = new Auto();
auto.setNummernschild("HH:MK:"+1);
LocalDate ld = LocalDate.now();
auto.setKaufdatum(ld);
session.beginTransaction();
for (int i=0; i<10; i++)
{
auto = new Auto();
auto.setNummernschild("HH:MK:"+i);
ld = LocalDate.now();
auto.setKaufdatum(ld);
Auto auto2 = new Auto();
auto2.setNummernschild("HH:MK:"+i);
ld = LocalDate.now();
auto2.setKaufdatum(ld);
//auto.setId(i);
Fahrer fahrer = new Fahrer();
fahrer.setVorname("Hans");
fahrer.setNachname("Huber");
Fahrer fahrer2 = new Fahrer();
fahrer2.setVorname("Anna");
fahrer2.setNachname("Schmidt");
double temp = Math.random();
int alter = (int)(temp*50);
fahrer.setAlter(alter);
fahrer2.setAlter(alter);
fahrer.setAuto(auto);
fahrer2.setAuto(auto2);
Wohnung wohnung = createWohnung(i);
wohnung.setFahrer(fahrer);
fahrer.setWohnung(wohnung);
Wohnung wohnung2 = createWohnung(i*10);
fahrer2.setWohnung(wohnung2);
wohnung2.setFahrer(fahrer2);
auto.getFahrers().add(fahrer);
auto2.getFahrers().add(fahrer2);
double zufall = Math.random()*100;
int zu = (int)zufall;
for (int z=0; z<zu; z++)
{
Fahrgast fahrgast = new Fahrgast();
fahrgast.setVornname("Hans"+z);
fahrgast.setNachname("Dampf"+z);
double kundennummer = Math.random()*10000;
fahrgast.setKundennummmer((int)kundennummer);
fahrgast.getAutos().add(auto);
fahrgast.getAutos().add(auto2);
auto.getFahrgasts().add(fahrgast);
auto2.getFahrgasts().add(fahrgast);
}
// session.save(fahrer);
// session.save(fahrer2);
session.save(auto);
session.save(auto2);
}
Fahrer abfrage = session.get(Fahrer.class, 2);
List<Fahrer>fahrers = session.createCriteria(Fahrer.class).list();
List<Fahrer>tobedeletet = new ArrayList<Fahrer>();
for (Fahrer aktuell : fahrers)
{
Auto car = aktuell.getAuto();
List<Fahrer>cardriver = car.getFahrers();
Fahrer temp = null;
for (Fahrer driver: cardriver)
{
if (driver.getId()==abfrage.getId())
{
tobedeletet.add(aktuell);
temp = driver;
}
}
cardriver.remove(temp);
session.update(car);
}
for (Fahrer aktuell : tobedeletet)
{
session.remove(aktuell);
}
System.out.println(abfrage.getVorname()+ " "+abfrage.getNachname());
session.getTransaction().commit();
session.close();
sf.close();
}
private Wohnung createWohnung(int i)
{
Wohnung wohnung = new Wohnung();
wohnung.setOrt("bla"+i);
wohnung.setStraße("blub"+i);
return wohnung;
}
}
finally the configuration file
<?xml version='1.0' encoding='utf-8'?>
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property
name="connection.driver_class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://192.168.2.252:5432/test</property>
<property name="connection.username">postgres</property>
<property name="connection.password">postgres</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<mapping class="mycode.Auto"/>
<mapping class="mycode.Fahrer"/>
<mapping class="mycode.Wohnung"/>
<mapping class="mycode.Fahrgast"/>
</session-factory>
Can anybody tell me, how to delete one of my drivers?
The error message:
ERROR: HHH000346: Error during managed flush [deleted object would be re-saved by cascade (remove deleted object from associations): [mycode.Fahrgast#3]]
Exception in thread "main" javax.persistence.EntityNotFoundException: deleted object would be re-saved by cascade (remove deleted object from associations): [mycode.Fahrgast#3]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:126)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1441)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:491)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3201)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2411)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68)
at mycode.Worker.work(Worker.java:133)
at mycode.Worker.main(Worker.java:19)
First things first, hope you know that alter is a reserved word, alter table <table_name>;, so you have to change your column name in Fahrer class:
#Column(name = "_alter") // choose any name you want
private int alter;
After that, why do you need so many bidirectional relationships? And look, you have:
class Fahrer {
// ...
#ManyToOne(cascade = CascadeType.ALL)
private Auto auto;
That means, when you delete a fahrer, the auto is deleted to. Is this realy what you want?
Now look at your code:
// at first you check if the ID is equal to abfrage and add it to list
if (driver.getId() == abfrage.getId()) {
tobedeletet.add(aktuell);
temp = driver;
}
// at the end you formed a list tobedeleted witch contains elements with the same ID.
for (Fahrer aktuell : tobedeletet) {
session.remove(aktuell);
}
To be honest, I'm a java beginner, so I may miss something. But deleting an entity with the same ID value a few times is propably not necessary.
Your exception says: remove deleted object from associations
It sould be enough just to remove the fahrer from the Auto#fahrers collection and update auto:
auto.getFahrers().remove(fahrer);
// remove other fahrers
session.update(auto);
Because you have a cascade=CascadeType.ALL property on your auto-to-fahrers relationship in Auto class, after updating the Auto, Fahrer should be deleted automaticly.
More about here: https://stackoverflow.com/a/11649941/6521788
And few things to notice:
PLEASE, use one language in your code :). Auto car = aktuell.getAuto();. You get auto, but the variable is called car...
PostgreSQLDialect is deprecated, choose PostgreSQL9Dialect or others in your hibernate config;
auto is a reserved name, better use something else.
Thanks to Oles,
I updated my code to
List<Auto>autos = session.createCriteria(Auto.class).list();
List<Auto>toBeUpdated = new ArrayList<Auto>();
for (Auto fahzeug : autos)
{
List<Fahrer>fahrers2 = fahzeug.getFahrers();
for (Fahrer aktuell : fahrers2)
{
if (aktuell.getId()==abfrage.getId())
{
toBeUpdated.add(fahzeug);
}
}
}
for (Auto fahrzeug : toBeUpdated)
{
fahrzeug.getFahrers().remove(abfrage);
System.out.println("removed");
session.update(fahrzeug);
}
Unfortunately still something doesn’t work as expected. I can’t do the remove inside the fahrerloop, because that ends with a concurrentmodificationexception. With the code posted here, there are no further exceptions. The debugging view shows me, that there are no drivers left for one of the cars after the last loop. Especially the driver with the id 2 gets deleted from the driver list. Unfortunately the driver remains in the database. That shouldn’t be the case, if I understood the last answer correctly.
Related
When creating threads using the Java Callable interface, I am having problems where the properties of an entity I have updated are not synced to the database, however when I do the work in the initial thread, they are. An example I have created below:
package peter.ford.entityupdate;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.enterprise.concurrent.ManagedExecutorService;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
#Named
#Stateless
public class EntityUpdateBean {
#PersistenceContext(unitName="peter.ford_EntityUpdate_war_1PU")
private EntityManager em;
#Resource
ManagedExecutorService mes;
private String newName;
public String getNewName() {
return newName;
}
public void setNewName(String newName) {
this.newName = newName;
}
public void update() {
UpdateThread t = new UpdateThread();
mes.submit(t);
}
private class UpdateThread implements Callable {
#Override
public Object call() throws Exception {
TypedQuery<Widget> q = em.createQuery("select w from Widget w", Widget.class);
List<Widget> widgets = q.getResultList();
try {
for ( Widget w : widgets) {
w.setName(newName);
}
} catch (Exception e) {
}
return 1;
}
}
}
Class Widget is the entity:
package peter.ford.entityupdate;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Widget implements Serializable {
#Id
#Column(name="ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name="Name")
private String name;
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;
}
}
If I change the code so that the work of looking up the entities and then setting the name is done from the update() method of EntityUpdateBean, the changes are updated in the database instantly. No errors appear to be raised, and following the thread in the debugger I can see that it is receiving a list of entities and updating them.
More broadly speaking, is this even the correct approach to update entities from a thread? In this case it is a trivial example, but I have a larger project where I need to update entities in bulk, while checking against data held on a disk for each one, and wish to do this in multiple threads reading from a queue, for performance reasons.
Welcome,
I have 2 classes: Conversation and Question. One Conversation have many questions.
Conversation.java:
package com.jcg.jpa.mappedBy;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name = "CONVERSATION_TABLE")
public class Conversation implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "CONV_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int conversationId;
#Column(name = "CONV_NAME")
private String name;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="conversation")
private Collection<Question> questions = new ArrayList<Question>();
public Conversation() { }
public int getConversationId() {
return conversationId;
}
public void setConversationId(int conversationId) {
this.conversationId = conversationId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<Question> getQuestions() {
return questions;
}
public void setQuestions(Collection<Question> questions) {
this.questions = questions;
}
#Override
public String toString() {
return "Employee [conversationId=" + conversationId + ", name=" + name + "]";
}
}
Question.java:
package com.jcg.jpa.mappedBy;
import java.io.Serializable;
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.Table;
#Entity
#Table(name = "QUESTION_TABLE")
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne
#JoinColumn(name = "CONVERSATION_CONV_ID", nullable = false)
private Conversation conversation;
#Column(name = "QUESTION_TEXT")
private String questionText;
#Column(name = "ANSWER_TEXT")
private String answerText;
public Question() { }
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getQuestionText() {
return questionText;
}
public void setQuestionText(String questionText) {
this.questionText = questionText;
}
public String getAnswerText() {
return answerText;
}
public void setAnswerText(String answerText) {
this.answerText = answerText;
}
public Conversation getConversation() {
return conversation;
}
public void setConversation(Conversation conversation) {
this.conversation = conversation;
}
#Override
public String toString() {
return "Question [id=" + id + ", questionText=" + questionText
+ ", answerText=" + answerText +"]";
}
}
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="JPAMappedbyExample" transaction-type="RESOURCE_LOCAL">
<class>com.jcg.jpa.mappedBy.Conversation</class>
<class>com.jcg.jpa.mappedBy.Question</class>
<!-- Configuring The Database Connection Details -->
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpatest" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="qwerty" />
</properties>
</persistence-unit>
And now in Main.java I'm trying to create Conversation with two questions:
package com.jcg.jpa.mappedBy;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class Main {
private static final EntityManagerFactory emFactoryObj;
private static final String PERSISTENCE_UNIT_NAME = "JPAMappedbyExample";
static {
emFactoryObj = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
}
// This Method Is Used To Retrieve The 'EntityManager' Object
public static EntityManager getEntityManager() {
return emFactoryObj.createEntityManager();
}
private static void insertRecords() {
EntityManager entityMgrObj = getEntityManager();
if (null != entityMgrObj) {
entityMgrObj.getTransaction().begin();
Conversation conv = new Conversation();
conv.setName("Discussion about something");
Question question1 = new Question();
question1.setQuestionText("2 plus 2");
question1.setAnswerText("four");
question1.setConversation(conv);
Question question2 = new Question();
question2.setQuestionText("what is Your name");
question2.setAnswerText("Adam");
question2.setConversation(conv);
List<Question> questions = new ArrayList<Question>();
questions.add(question1);
questions.add(question2);
conv.setQuestions(questions);
entityMgrObj.persist(conv);
entityMgrObj.getTransaction().commit();
entityMgrObj.clear();
System.out.println("Record Successfully Inserted In The Database");
}
}
public static void main(String[] args) {
insertRecords();
}
}
In insertRecords() I'm creating conv and two questions.
each of questions has set conversation:
question1.setConversation(conv);
question2.setConversation(conv);
Next, a question list which contains these 2 questions is created
and set to conv questions list:
conv.setQuestions(questions);
An it is working ok, because data is inserted into both tables,
and foreign key CONVERSATION_CONV_ID is filled:
However when I remove setting conversation in questions, lines:
question1.setConversation(conv);
question2.setConversation(conv);
foreign key is set to NULL. Why? We already added two questions to conversation questions list:
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="conversation")
private Collection<Question> questions = new ArrayList<Question>();
, so hibernate should know what is conversation foreign key for these two questions (because they are located on specified conversation questions list). So is it possible to avoid setting Conversation for each of the questions and only add questions to Conversation's question list ? How should I configure entities to do that? Or maybe it's impossible and we always need to set it both directions?
so hibernate should know what is conversation foreign key for these two questions (because they are located on specified conversation questions list).
No Hibernate shouldn't know what is the Conversation of these two Questions if you don't specify it using setConversation(), because it's dealing with objects here, and these two questions doesn't have any indication on which Conversation they are part of.
Explanation:
Because when you only add these two questions to the Conversation object, this information won't be visible in the Questions objects.
Another thing here, the mappedBy attribute is indicating wich object is the owner of the mapping, so how can the mapping be made if there's no given object in the mappedBy side?
That's why you should specify the Conversation in Question object, so the mapping can be correctly evaluated by Hibernate.
Note:
It's recommended to use a Set for OneToMany mapping rather than any other Collection, because this collection shouldn't have any duplicates, so you better change it to:
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="conversation")
private Set<Question> questions = new HashSet<Question>();
TrainingDays.java
package com.hibernate;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name = "TrainingDays")
public class TrainingDays {
#Id
#GeneratedValue
private int TD_Id;
private String T_Days;
public int getTD_Id() {
return TD_Id;
}
public void setTD_Id(int tD_Id) {
TD_Id = tD_Id;
}
public String getT_Days() {
return T_Days;
}
public void setT_Days(String t_Days) {
T_Days = t_Days;
}
#OneToMany(cascade={CascadeType.ALL})
#JoinColumn(name="TD_Id")
private Set<TrainingTime> trainingTime;
public Set<TrainingTime> getTrainingTime() {
return trainingTime;
}
public void setTrainingTime(Set<TrainingTime> trainingTime) {
this.trainingTime = trainingTime;
}
}
TrainingTime.java
package com.hibernate;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name = "TrainingTime")
public class TrainingTime {
#Id
#GeneratedValue
private int TT_Id;
#ManyToOne
#JoinColumn(name = "TD_Id")
private TrainingDays trainingDays;
private String time;
private String desc;
public int getTT_Id() {
return TT_Id;
}
public void setTT_Id(int tT_Id) {
TT_Id = tT_Id;
}
public TrainingDays getTrainingDays() {
return trainingDays;
}
public void setTrainingDays(TrainingDays trainingDays) {
this.trainingDays = trainingDays;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
Hibernate.cfg.xml
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<session-factory>
<property name="hbm2ddl.auto">update</property>
<property name="dialect">org.hibernate.dialect.OracleDialect</property>
<property name="connection.url">jdbc:oracle:thin:#localhost:1521:xe</property>
<property name="connection.username">blueHeaven</property>
<property name="connection.password">123456</property>
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<mapping class="com.hibernate.Rodie" />
<mapping class="com.hibernate.TrainingTime" />
<mapping class="com.hibernate.TrainingDays" />
</session-factory>
In the database TraningDays table is created but traningTime table is not created.
Can any one help?
Please correct your code as given:
class TrainingDays
#Entity
#Table(name = "TrainingDays")
public class TrainingDays {
#OneToMany(cascade={CascadeType.ALL},mappedBy = "trainingDays")
private Set<TrainingTime> trainingTime;
}
class TrainingTime
#Entity
#Table(name = "TrainingTime")
public class TrainingTime {
#ManyToOne
#JoinColumn(name = "TD_Id")
private TrainingDays trainingDays;
}
You need to specify "mappedBy" when you are creating bidirectional
relationship.
As the mapping is bidirectional. Please try like this.
TrainingDays.java
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name = "TrainingDays")
public class TrainingDays implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="TD_Id")
private int TD_Id;
#Column(name="T_Days")
private String T_Days;
#OneToMany(mappedBy="trainingDays")
private Set<TrainingTime> trainingTime;
public int getTD_Id() {
return TD_Id;
}
public void setTD_Id(int tD_Id) {
TD_Id = tD_Id;
}
public String getT_Days() {
return T_Days;
}
public void setT_Days(String t_Days) {
T_Days = t_Days;
}
public Set<TrainingTime> getTrainingTime() {
return trainingTime;
}
public void setTrainingTime(Set<TrainingTime> trainingTime) {
this.trainingTime = trainingTime;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
TrainingTime.java
import java.io.Serializable;
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.Table;
#Entity
#Table(name = "TrainingTime")
public class TrainingTime implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="TT_Id")
private int TT_Id;
#Column(name="time")
private String time;
#Column(name="desc")
private String desc;
#ManyToOne
#JoinColumn(name="TD_Id")
private TrainingDays trainingDays;
public int getTT_Id() {
return TT_Id;
}
public void setTT_Id(int tT_Id) {
TT_Id = tT_Id;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public TrainingDays getTrainingDays() {
return trainingDays;
}
public void setTrainingDays(TrainingDays trainingDays) {
this.trainingDays = trainingDays;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
Always try to apply mappings after declaring all the columns.
I got the Solution of this issue,
in TrainingTime Pojo class i have created one variable named "Desc", and i found that this keyword is already reserved, so can name any variable like this.
I am using Hibernate to persist data to two tables in postgres, recently I did some changes in the table structure and I decided to create another database, always using Postgres of course, when I try to run the java code I figured out that hibernate is always looking for the old table structure; to be sure, I decided to delete the old table in the DBMS but still hibernate is looking for the old table stucture, in fact, I noticed this because a field does not exist anymore in the newest design. My question is: is there a way to update this in Hibernate? where shall I look for? I am using Eclipse Mars, I clean up my project and restart it but still the same.
Here it is my hibernate.cfg.xml
enter code here
<?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>
<!-- Database connection settings -->
<property name="connection.driver.class">org.postgresql.Driver</property>
<property name="connection.url">jdbc:postgresql://localhost:5432/cineticket2</property>
<property name="connection.username">ok</property>
<property name="connection.password">ok123$</property>
<!-- SQL Dialect -->
<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<mapping class="sv.edu.ucad.et1.cineticket.data.entities.Usuarios"/>
<mapping class="sv.edu.ucad.et1.cineticket.data.entities.Cargos"/>
<mapping class="sv.edu.ucad.et1.cineticket.data.entities.Departamentos"/>
</session-factory>
</hibernate-configuration>
my HibernateUtil.java is:
package sv.edu.ucad.et1.cineticket.data;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import sv.edu.ucad.et1.cineticket.data.entities.Cargos;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try{
//Configuration configuration = new Configuration();
//return configuration.buildSessionFactory(new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build());
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
Metadata mdata = new MetadataSources(ssr).getMetadataBuilder().build();
return mdata.getSessionFactoryBuilder().build();
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException("Ocurrio un error en la construcction de la Sesion Factory");
}
}//fin de buildSessionfactory
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
}//fin de HibernateUitl
Here it is my Departamentos.java
package sv.edu.ucad.et1.cineticket.data.entities;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Access;
import javax.persistence.AccessType;
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.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
#Entity
#Table(name="departamentos")
#Access(value=AccessType.PROPERTY) //acceso a traves de getters
public class Departamentos {
private Long coddep;
private String nomdep;
private String desdep;
private boolean estdep;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="coddep", updatable=false)
public Long getCoddep() {
return coddep;
}
public void setCoddep(Long coddep) {
this.coddep = coddep;
}
#Column(name="nomdep", nullable=false)
public String getNomdep() {
return nomdep;
}
public void setNomdep(String nomdep) {
this.nomdep = nomdep;
}
#Column(name="desdep", nullable=false)
public String getDesdep() {
return desdep;
}
public void setDesdep(String desdep) {
this.desdep = desdep;
}
#Column(name="estdep", nullable=false)
public boolean isEstdep() {
return estdep;
}
public void setEstdep(boolean estdep) {
this.estdep = estdep;
}
}
This is my Usuarios.java
package sv.edu.ucad.et1.cineticket.data.entities;
import java.util.Date;
import javax.persistence.Access;
import javax.persistence.AccessType;
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.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
#Entity
#Table(name="usuarios")
#Access(value=AccessType.PROPERTY) //acceso a traves de getters
public class Usuarios {
private Long codusu;
private String apeusu;
private String nomusu;
private String celusu;
private String dirusu;
private Date fcousu;
private String cueusu;
private String clausu;
private Long codsuc;
private Long codcar;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="coddep")
public Departamentos deptos;
#Transient
public Departamentos getDeptos() {
return deptos;
}
public void setDeptos(Departamentos deptos) {
this.deptos = deptos;
}
//propiedad bandera, que se declara como #Transient
private boolean estado;
#Transient
public boolean isEstado() {
return estado;
}
public void setEstado(boolean estado) {
this.estado = estado;
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="codusu", updatable=false)
public Long getCodusu() {
return codusu;
}
public void setCodusu(Long codusu) {
this.codusu = codusu;
}
#Column(name="apeusu", nullable=false)
public String getApeusu() {
return apeusu;
}
public void setApeusu(String apeusu) {
this.apeusu = apeusu;
}
#Column(name="nomusu", nullable=false)
public String getNomusu() {
return nomusu;
}
public void setNomusu(String nomusu) {
this.nomusu = nomusu;
}
#Column(name="celusu", nullable=false)
public String getCelusu() {
return celusu;
}
public void setCelusu(String celusu) {
this.celusu = celusu;
}
#Column(name="dirusu")
public String getDirusu() {
return dirusu;
}
public void setDirusu(String dirusu) {
this.dirusu = dirusu;
}
#Column(name="cueusu", nullable=false)
public String getCueusu() {
return cueusu;
}
public void setCueusu(String cueusu) {
this.cueusu = cueusu;
}
#Column(name="clausu", nullable= false)
public String getClausu() {
return clausu;
}
public void setClausu(String clausu) {
this.clausu = clausu;
}
public Long getCodsuc() {
return codsuc;
}
public void setCodsuc(Long codsuc) {
this.codsuc = codsuc;
}
#Column(name="codsal", nullable=false)
public Long getCodsal() {
return codsuc;
}
public void setCodsal(Long codsal) {
this.codsuc = codsal;
}
#Column(name="codcar", nullable=false)
public Long getCodcar() {
return codcar;
}
public void setCodcar(Long codcar) {
this.codcar = codcar;
}
#Column(name="fcousu")
public Date getFcousu() {
return fcousu;
}
public void setFcousu(Date fcousu) {
this.fcousu = fcousu;
}
}//fin de Usuarios
this is the main class:
package sv.edu.ucad.et1.cineticket.data;
import java.util.Date;
import org.hibernate.Session;
import sv.edu.ucad.et1.cineticket.data.entities.Departamentos;
import sv.edu.ucad.et1.cineticket.data.entities.Usuarios;
public class UnoaMuchosDemo {
public static void main(String[] args){
Session sesion = HibernateUtil.getSessionFactory().openSession();
//inicio de la transaccion
try{
org.hibernate.Transaction transaccion = sesion.beginTransaction();
Departamentos deptos = createNewDepartamentos();
Usuarios usuarios = createNewUsuarios(deptos);
sesion.save(usuarios);
transaccion.commit();
}catch(Exception e){
e.printStackTrace();
}finally{
sesion.close();
HibernateUtil.getSessionFactory().close();
}
}
//clases empotradas que crean usuarios y deptos
//crea un nuevo usuario
private static Usuarios createNewUsuarios(Departamentos deptos) {
Usuarios nusu = new Usuarios();
nusu.setApeusu("Messi");
nusu.setNomusu("Lionel");
nusu.setCelusu("7588-8888");
nusu.setDirusu("Camp Nou, Barcelona, Catalunya");
nusu.setFcousu(new Date());
nusu.setCueusu("messi#barcelona.com");
nusu.setClausu("12345");
nusu.setDeptos(deptos);
nusu.setCodcar((long) 1);
nusu.setCodsuc((long) 1);
return nusu;
}
//crea un nuevo depto
private static Departamentos createNewDepartamentos() {
Departamentos ndepto = new Departamentos();
ndepto.setNomdep("Finanzas");
ndepto.setDesdep("Contabilidad, Tesoreria");
ndepto.setEstdep(true);
return ndepto;
}
}//fin de la clase Principal
and the error:
as you can see, the table structure in the query does not correspond to the actual -you may refer to Usuarios.java
All the best
Please, check out 'Usuarios.java' file. It still has 'codsal':
#Column(name="codsal", nullable=false)
public Long getCodsal() {
return codsuc;
}
public void setCodsal(Long codsal) {
this.codsuc = codsal;
}
That's why hibernate still looks for that column on new database.
Is there anyway I can have the effect of #ElementCollection without actually having this annotation? I am using Hibernate 3.3, while #ElementCollection and #CollectionTable is only supported for Hibernate 3.5 and beyond. But I really need to use these annotations, for a case like this:
http://www.concretepage.com/hibernate/elementcollection_hibernate_annotation
(Where we get the List of Strings rather than List of the full entity)
You can use the <element> tag to do the same operation, refer to this link from hibernate documentation:
7.2.3. Collections of basic types and embeddable objects
The example given in the link is :
<element
column="column_name" (1)
formula="any SQL expression" (2)
type="typename" (3)
length="L"
precision="P"
scale="S"
not-null="true|false"
unique="true|false"
node="element-name"
/>
1 column (optional): the name of the column holding the collection element values.
2 formula (optional): an SQL formula used to evaluate the element.
3 type (required): the type of the collection element.
Refer to this link for an example:
Collection Mapping
Star.java
private Set<String> planets = new HashSet<String>();
Star.hbm.xml
<set name="planets" table="star_planet">
<key column="star_id" />
<element type="text"/>
</set>
Update:
You have to use either xml mapping or annotations for a given entity class but not both at a time.
If you want to see examples only using annotations then there are so many available if you search in Google, please check and let me know if you have issues in implementing them.
Finally, yes it works with Set of Strings, integers or Long etc.
Update:
Here is a simple example that shows how to use element collections:
User.java
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
#Entity
#Table(name = "TB_User")
public class User {
#Id
#GeneratedValue
private int id;
private String name;
#ElementCollection
#CollectionTable(name = "Addresses", joinColumns = #JoinColumn(name = "user_id"))
#AttributeOverrides({ #AttributeOverride(name = "street1", column = #Column(name = "fld_street")) })
public Set<Address> addresses = new HashSet<Address>();
public User() {
}
public User(String name, Address... addresses){
this.name = name;
this.addresses.addAll(Arrays.asList(addresses));
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Address> getAddresses() {
return addresses;
}
public void setAddresses(Set<Address> addresses) {
this.addresses = addresses;
}
}
Address.java
import javax.persistence.Embeddable;
#Embeddable
public class Address {
private String street1;
public Address() {
}
public Address(String street1) {
this.street1 = street1;
}
public String getStreet1() {
return street1;
}
public void setStreet1(String street1) {
this.street1 = street1;
}
#Override
public String toString() {
return street1;
}
}
Simple logic to test this:
private static void showUsers() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.getTransaction().begin();
List<User> users = session.createQuery("from User").list();
for (User user : users) {
System.out.println(user.getName() + " -- > " + user.getAddresses());
}
session.getTransaction().commit();
}
private static void saveUsers() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.getTransaction().begin();
User user1 = new User("U1", new Address("A1"), new Address("A11"));
User user2 = new User("U2", new Address("A2"));
session.save(user1);
session.save(user2);
session.getTransaction().commit();
}