I have 2 tables, testInput and testCases and in testInput i have a FK with the id of the other table.
So basically the rows I want to delete are id of the input, id of the testCase, name and a description.
'43', '21', 'USERNAME', 'USERNAME'
'44', '21', 'PASSWORD', 'PASSWORD'
I tried to delete that row and I get
java.sql.SQLIntegrityConstraintViolationException: Cannot delete or
update a parent row: a foreign key constraint fails
(mydb.testInput, CONSTRAINT fk02 FOREIGN KEY (testCase)
REFERENCES testCases (idtestCase) ON DELETE NO ACTION ON UPDATE NO
ACTION)
I don't want to delete the record of testCase. I just want to delete the inputs of that testCase. What do I do?
code if u want...
List<TestInput> previousInputs = TestInput.getInputs(testCaseName);
for(TestInput in : previousInputs) {
Database.deleteObject(in);
}
//delete the object to the database
public static void deleteObject(Object object) {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Transaction tx = null;
try{
tx = session.beginTransaction();
session.delete(object);
tx.commit();
}catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}finally {
session.close();
}
}
xml TestCases
<hibernate-mapping>
<class name="TestCase" table="testCases">
<meta attribute="class-description">
This class contains the testCases details.
</meta>
<id name="id" type="int" column="idtestCase">
<generator class="native"/>
</id>
<property name="name" column="name" type="string"/>
<many-to-one name="type" class="TestType" column="type" fetch="select" lazy="false"/>
<property name="data" column="data" type="binary"/>
<property name="amountOfInputs" column="amountOfInputs" type="int"/>
<property name="creationDate" column="creationDate" type="string"/>
<property name="createdBy" column="createdBy" type="string"/>
<many-to-one name="tellerConfig" class="TellerConfiguration" column="tellerConfig" fetch="select" lazy="false"/>
</class>
</hibernate-mapping>
xml testInput
<hibernate-mapping>
<class name="TestInput" table="testInput">
<meta attribute="class-description">
This class contains the testCases input details.
</meta>
<id name="id" type="int" column="idtestInput">
<generator class="native"/>
</id>
<property name="name" column="name" type="string"/>
<property name="description" column="description" type="string"/>
<many-to-one name="testCase" class="TestCase" column="testCase" fetch="select" cascade="all" lazy="false" />
</class>
Change the constraint on the foreign key fk02 from ´NO ACTION´ to 'SET NULL'
FOREIGN KEY (idtestcase)
REFERENCES testCases(idtestCase)
ON DELETE SET NULL
Related
I am trying one-to-one mapping from statusHistoryLogs to element in hibernate. I am new in Hibernate. I have added one to one mapping in element.hbm.xml also.
I am getting the following error: Duplicate property mapping of element found in com.ot.entry.members.StatusHistoryLog.
Please guide me, where I am going wrong. Please correct my code.
StatusHistoryLog.hbm.xml
<hibernate-mapping>
<class dynamic-insert="true" dynamic-update="true" name="com.ot.entry.members.StatusHistoryLog" table="status_history_logs">
<id name="id" type="long">
<column name="id" sql-type="integer"/>
<generator class="native"/>
</id>
<property name="element" length="11" column="element_id" type="integer" />
<property name="status" length="11" column="status_id" type="integer" />
<one-to-one name="element" class="com.ot.entry.members.Element" constrained="true"/>
<property name="period" type="period">
<column name="start_date" not-null="true"/>
<column name="end_date"/>
</property>
</class>
</hibernate-mapping>
element.hbm.xml
<hibernate-mapping>
<class dynamic-insert="true" dynamic-update="true" name="com.ot.entry.members.Element" abstract="true" table="members">
<id name="id" type="long">
<column name="id" sql-type="integer"/>
<generator class="native"/>
</id>
<discriminator column="subclass" type="string" length="1"/>
<property name="name" length="100" column="name" type="string" not-null="true"/>
<property name="creationDate" column="creation_date" type="calendar" not-null="true"/>
<many-to-one name="group" class="com.ot.entry.groups.Group">
<column name="group_id" not-null="true" sql-type="integer"/>
</many-to-one>
<property name="status" column="status" not-null="false" length="1">
<type name="com.paynet.utils.hibernate.StringValuedEnumType">
<param name="enumClassName">com.ot.entry.members.Element$Status</param>
</type>
</property>
<property name="email" length="100" column="email" type="string" index="ix_email"/>
<property name="notificationLanguage" column="notification_language" length="6" not-null="false">
<type name="com.paynet.utils.hibernate.StringValuedEnumType">
<param name="enumClassName">com.ot.entry.settings.LocalSettings$Language</param>
</type>
</property>
<one-to-one name="user" cascade="all" class="com.ot.entry.access.User" />
<one-to-one name="statusHistoryLogs" cascade="all" class="com.ot.entry.members.StatusHistoryLog" />
<bag name="groupHistoryLogs" cascade="delete" inverse="true" order-by="start_date">
<key>
<column name="element_id" sql-type="integer"/>
</key>
<one-to-many class="com.ot.entry.groups.GroupHistoryLog"/>
</class>
</hibernate-mapping>
StatusHistoryLog.java
public class StatusHistoryLog extends Entity {
private static final long serialVersionUID = 68407121216377438L;
private Element element;
private Status status;
private Period period;
public Element getElement() {
return element;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public Period getPeriod() {
return period;
}
public void setElement(final Element element) {
this.element = element;
}
public void setPeriod(final Period period) {
this.period = period;
}
#Override
public String toString() {
String string = getId() + ": " + getStatus().getValue() + " - begin: " + period.getBegin();
if (period.getEnd() != null) {
string += " - end: " + period.getEnd();
}
return string;
}
}
<property name="element" length="11" column="element_id" type="integer" />
should be
<property name="elementId" length="11" column="element_id" type="integer" />
I have the following issue :
org.hibernate.NonUniqueObjectException:
A different object with the same identifier value was already associated with the session.
Strangely it does not occurs systematically.
Entity is loaded from database to Struts and set in HTTP Session.
Once modified it's send to business service for saving.
(sessionFactory.update, sessionFactory.save)
It should always have hibernate issue but the org.hibernate.NonUniqueObjectException occurs only some times (Don't know why)
Does any one have an explanation ?
I think about reload the object from hibernate session in my business service and copy data from entity object from Struts HTTP Session.
#Override
public boolean equals(Object autre) {
if (this == autre) {
return true;
}
if ((autre == null) || (autre.getClass() != this.getClass())) {
return false;
}
MouvementFinancier entite = (MouvementFinancier) autre;
if (pk == null || entite.pk == null) {
return false;
}
return pk.equals(entite.pk);
}
#Override
public int hashCode() {
if (pk == null) {
return super.hashCode();
}
return pk.hashCode();
}
Hibernate mapping
<class name="com.XXX.MouvementFinancier" table="MOUVEMENT_FINANCIER"
discriminator-value="0" abstract="true">
<id name="pk" type="integer" column="PK_MOUVEMENT_FINANCIER" unsaved-value="null">
<generator class="com.XXX.TableGenerator">
<param name="segment_value">MOUVEMENT_FINANCIER</param>
</generator>
</id>
<discriminator column="CLASSE" type="integer" />
<timestamp column="DATE_VERSION" name="version" unsaved-value="null" />
<property name="commentaire" column="COMMENTAIRE" />
...
<set name="actes" cascade="all,delete-orphan" fetch="select" sort="natural">
<key column="PK_MOUVEMENT_FINANCIER" not-null="true" />
<one-to-many class="com.p****.HistoriqueMouvement" />
</set>
<subclass name="com.XXX.Encaissement" discriminator-value="2">
<property name="purpose" column="NATURE_RECUPERATION" />
...
<many-to-one name="emetteur" column="PK_PERSONNE_EMETTEUR"
class="com.XXX.Personne" cascade="none" fetch="join" lazy="false"/>
<many-to-one name="acteurEmetteur" column="PK_ACTEUR_EMETTEUR"
class="com.XXX.Acteur" cascade="none" fetch="join" lazy="false"/>
</subclass>
<subclass name="com.XXX.Reglement" discriminator-value="1">
<property name="dateAutorisation" type="timestamp" column="DATE_AUTORISATION" />
<property name="franchise" column="FRANCHISE" />
...
<many-to-one name="beneficiaire" column="PK_PERSONNE_BENEFICIAIRE"
class="com.XXX.Personne" cascade="none" fetch="join" lazy="false"/>
<many-to-one name="acteurBeneficiaire" column="PK_ACTEUR_BENEFICIAIRE"
class="com.XXX.Acteur" cascade="none" fetch="join" lazy="false"/>
<many-to-one name="adresseCourrierReglementBeneficiaire" column="PK_ADD_COUR_REG_BENEF"
class="com.XXX.AdresseCourrierReglement" cascade="none" fetch="join" lazy="false"/>
<many-to-one name="destinataire" column="PK_PERSONNE_DESTINATAIRE"
class="com.XXX.Personne" cascade="none" fetch="join" lazy="false"/>
<many-to-one name="acteurDestinataire" column="PK_ACTEUR_DESTINATAIRE"
class="com.XXX.Acteur" cascade="none" fetch="join" lazy="false"/>
<many-to-one name="adresseCourrierReglementDestinataire" column="PK_ADD_COUR_REG_DEST"
class="com.XXX.AdresseCourrierReglement" cascade="none" fetch="join" lazy="false"/>
<many-to-one name="rib" column="PK_RIB" class="com.XXX.assureur.RIB"
cascade="all" fetch="select" />
<set name="ventilationDepenses" cascade="all,delete-orphan" fetch="select">
<key column="PK_MOUVEMENT_FINANCIER" not-null="true" />
<one-to-many class="com.XXX.Depense"/>
</set>
</subclass>
</class>
<class name="com.XXXX.Depense" table="VENTILATION_DEPENSES">
<id name="pk" type="integer" column="PK_VENTILATION_DEPENSE" unsaved-value="null">
<generator class="com.XXX.TableGenerator">
<param name="segment_value">VENTILATION_DEPENSES</param>
</generator>
</id>
<property name="nature" column="CODE_NATURE_DEPENSE" />
<property name="montant" column="MONTANT_DEPENSE" />
...
</class>
Issue has been solved by using Hiberante merge in DAO
But I still wonder why in most case there was no issue to send back a "detached" entity to service layer without using merge command or copy in an entity loaded from hibernate session.
// TODO : save (twice) replaced by 1 merge to avoid issue on detached object
// if we have any more pb on this, redo all : load payment from session and copy data in from dto.
session.merge(reglement);
Complete code
#Override
public void update...(...) {
if (logger.isDebugEnabled()) {
logger.debug("Updating a settlement");
}
Session session = sf.getCurrentSession();
final PartieFinanciere partieReglement = (PartieFinanciere) session.get(PartieFinanciere.class, pkPartieFinanciere);
if (partieReglement == null) {
throw new ExceptionPkEntiteInconnu(PartieFinanciere.class, pkPartieFinanciere);
}
// History : last movement amount to remove it on total amount
HistoriqueMouvement movementHistoryLast = reglement.getActes().stream().sorted((h1, h2) -> h2.compareTo(h1)).findFirst().orElse(null);
Double mouvementLastAmount = movementHistoryLast != null ? movementHistoryLast.getMontant() : 0;
// History : add movement modification in history
HistoriqueMouvement histo = new HistoriqueMouvement();
histo.setActe(...);
histo.setDate(...);
histo.setMontant(...);
.....
reglement.getActes().add(histo);
partieReglement.getMouvements().add(reglement);
// Recalculate total amount : remove previous movement amount, set movement modified amount
Double amountProvision = ofNullable(partieReglement.getTotalMouvements()).orElse(0.0).doubleValue() - mouvementLastAmount + reglement.getMontant();
partieReglement.setTotalMouvements(amountProvision);
if (logger.isDebugEnabled()) {
logger.debug("Updating total mouvement and suspens.");
}
mettreAJourTotalMouvementsEtSuspens(session, partieReglement);
ajouterActePartieFinanciere(gestionnaire, partieReglement, getHistoriquePartieActe(null, reglement.getType(), false), reglement.getMontant());
// TODO : save (twice) replaced by 1 merge to avoid issue on detached object
// if we have any more pb on this, redo all : load payment from session and copy data in from dto.
session.merge(reglement);
}
I have about 5000 rows to insert to my database using hibernate, but it lasts about 2 minutes, I have no idea why. Here is my code:
hibernate.cfg.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/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://sql.user.nazwa.pl:3307/user</property>
<property name="hibernate.jdbc.batch_size">20</property>
<property name="hibernate.connection.username">user</property>
<property name="hibernate.connection.password">pasword</property>
<property name="show_sql">false</property>
<mapping resource="model/models.hbm.xml"/>
</session-factory>
</hibernate-configuration>
models.hbm.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="model.User" table="User">
<id name="userId" type="int" column="userId">
<generator class="native"/>
</id>
<property name="userName" column="userName" type="string"/>
<property name="height" column="height" type="double"/>
<property name="weight" column="weight" type="double"/>
<property name="hrMax" column="hrMax" type="double"/>
<property name="hrMin" column="hrMin" type="double"/>
<set name="trainings" cascade="all-delete-orphan,save-update" lazy="false">
<key column="userId"/>
<one-to-many class="model.Training"/>
</set>
</class>
<class name="model.Training" table="Training">
<id name="trainingId" type="int" column="trainingId">
<generator class="native"/>
</id>
<property name="type" column="type" type="string"/>
<property name="date" column="date" type="string"/>
<property name="duration" column="duration" type="org.hibernate.type.LocalTimeType"/>
<property name="totalDistance" column="totalDistance" type="double"/>
<property name="averageHeartRate" column="averageHeartRate" type="int"/>
<property name="averageSpeed" column="averageSpeed" type="double"/>
<property name="maxSpeed" column="maxSpeed" type="double"/>
<property name="calories" column="calories" type="int"/>
<property name="fatPercentageOfCalories" column="fatPercentageOfCalories" type="int"/>
<set name="trainingDetails" cascade="all-delete-orphan,save-update" lazy="false">
<key column="trainingId"/>
<one-to-many class="model.TrainingDetails"/>
</set>
</class>
<class name="model.TrainingDetails" table="TrainingDetails">
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="time" column="time" type="org.hibernate.type.LocalTimeType"/>
<property name="heartRate" column="heartRate" type="int"/>
<property name="speed" column="speed" type="double"/>
<property name="altitude" column="altitude" type="int"/>
<property name="distance" column="distance" type="double"/>
</class>
</hibernate-mapping>
HibernateUtil.java:
package model;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* Created by Piotr on 2015-10-11.
*/
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
Method that executes too long:
public void addTrainingsDetailsToTraining(Map<String, String> mapOne, Map<String, ArrayList<String>> mapTwo
, int trainingId, int rowCount) {
Session session = hibernateUtil.getSessionFactory().openSession();
session.setCacheMode(CacheMode.IGNORE);
Transaction tx = null;
try {
tx = session.beginTransaction();
Training training = (Training) session.get(Training.class, trainingId);
for (int i = 0; i < rowCount; i++) {
training.getTrainingDetails().add(new TrainingDetails(LocalTime.parse(mapTwo.get(time).get(i))
, Integer.parseInt(mapTwo.get(heartRate).get(i)), Double.parseDouble(mapTwo.get(speed).get(i))
, Integer.parseInt(mapTwo.get(altitude).get(i)), Double.parseDouble(mapTwo.get(distance).get(i))));
if (i % 20 == 0) {
session.flush();
session.clear();
}
}
session.update(training);
tx.commit();
} catch (Exception e) {
if (tx != null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
If your design allows you could give plain SQL a change (or maybe there is also a HQL equivalent).
I guess the INSERT ... ON DUPLICATE KEY UPDATE Syntax should be way faster when upserting multiple data with VALUES:
http://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html
I have 2 class Item & Type. An Item belongs to one type.
It works ok. But when I try to change TYPE of an already saved item, it brings out the error:
identifier of an instance of com.myapp.model.Type was altered from 1
to 2.
It seems that Hibernate is thinking that I try to edit the id of Type. Actually, I want to change the Type of an item, not edit the type it is in. For a quick example, I have an Item name "Ball" belongs to "sport" type, but now I want to change it to "Tool" type. And Hibernate think that I want to change the name (and Id) of "Sport" type into "Tool"!
Pseudo code:
Item item = getItemFromDatabase(itemId);
item.setType(newType);
saveItem(item);
My mapping files:
<hibernate-mapping>
<class name="com.myapp.model.Item" table="ITEM">
<cache usage="read-write"/>
<id name="id" column="ID">
<generator class="sequence">
<param name="sequence">item_seq</param>
</generator>
</id>
<property name="name" column="NAME"/>
<many-to-one name="type"
class="com.myapp.model.Type"
column="type_id"
foreign-key="ITEM_TYPE_FK"
/>
<property name="description" column="DESCRIPTION"/>
</class>
</hibernate-mapping>
And
<hibernate-mapping>
<class name="com.myapp.model.Type" table="TYPE">
<cache usage="read-write"/>
<id name="id" column="ID">
<generator class="sequence">
<param name="sequence">type_seq</param>
</generator>
</id>
<property name="name" column="NAME"/>
</class>
</hibernate-mapping>
Does I misunderstand anything?
UPDATE:
I have an Hibernate utility function like this:
#Override
#SuppressWarnings("unchecked")
public <T> T getById(Class<T> entityClass, Serializable id) {
try {
Object result = this.sessionFactory.getCurrentSession().get(entityClass, id);
if (result != null) {
return (T)result;
} else {
return null;
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new DataAccessException(e);
}
}
Then in my code, I just call:
Type updatedType = repository.getById(Type.class, item.getType().getId());
The way that I think is correct is
Item item = getItemFromDatabase(itemId);
item.setType(getItemTypeFromDatabase(newTypeId));
saveItem(item);
I am using hibernate in my java program and I got some troubles using it ..
Here is my xml:
<hibernate-mapping>
<class name="revEngMapping.TestNetwork" table="testNetwork">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<property name="networkElementId" type="string">
<column name="networkElement_id" length="45" />
</property>
<property name="date" type="string">
<column name="Date" length="45" />
</property>
<property name="oid" type="string">
<column name="Oid" length="150" />
</property>
<property name="value" type="string">
<column name="Value" length="200" />
</property>
</class>
here is my java class:
public class TestNetwork implements java.io.Serializable {
private Integer id;
private String networkElementId;
private String date;
private String oid;
private String value;
public TestNetwork() {
}
public TestNetwork(String networkElementId, String date, String oid,
String value) {
this.networkElementId = networkElementId;
this.date = date;
this.oid = oid;
this.value = value;
}
Then its just getters and setters, and in my main, I just want to display it:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Criteria crit = session.createCriteria(TestNetwork.class);
List resultList=crit.list();
for(int i=0;i<resultList.size();i++)
System.out.println(((TestNetwork)resultList.get(i)).getId()+" "+((TestNetwork)resultList.get(i)).getDate());
session.getTransaction().commit();
In my console it says that I have an SQL error ..
10:20:54,626 WARN JDBCExceptionReporter:233 - SQL Error: 1064, SQLState: 42000
10:20:54,628 ERROR JDBCExceptionReporter:234 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.testNetwork this_' at line 1
Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not execute query
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:92)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.loader.Loader.doList(Loader.java:2536)
Hope s.one can help. thanks
mysql requires you to use backticks `` when accessing table names & columns, please back ticks while defining
eg..
<property name="someProperty" column="`dbColumnName`"/>
this should solve your problem..
Anantha Sharma