-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 
Author Message
 Post subject: Sauvegarde d'un graph d'objet : updates inutiles ?
PostPosted: Wed Jun 15, 2005 10:21 am 
Newbie

Joined: Wed Jun 15, 2005 9:18 am
Posts: 11
Bonjour,

Je rencontre un petit soucis avec Hibernate dans le cadre de la sauvegarde d'un graph d'objet. Pas bien grave puisque tout est sauvegardé comme il faut sans violation des contraintes mais j'ai deux requête qui ne me semble pas nécessaire.

Un membre (class Member) a une adresse (class Address).
Une adresse (class Address) à un et un seul un pays (class Country).
Un membre a un set (java.util.Set) de qualifications (class Qualification)
Une qualification (class Qualification) est rattachée à un et un seul diplôme (class Degree)


Toutes les foreign keys entre les tables T_MEMBER, T_DEGREE, T_ADDRESS, T_COUNTRY et T_QUALIFICATION sont activées en base, les valeurs nulles sont interdites pour les colonnes correspondantes aux foreign keys.

Dans une classe de test je créé un nouveau membre (appelons le member), auquel j'affecte une nouvelle adresse (à qui j'affecte un pays existant) et deux nouvelles qualifications (à chacune d'elle j'affecte un diplôme existant).

Une fois que le graph d'objet 'member' correspond à ce que je veux sauvegarder je fais un session.save sur 'member'.

Tout se passe bien (les requêtes sont exécutés dans le bon ordre et les contraintes ne sont pas violées) mais Hibernate semble exécuter deux requêtes qui ne me paraissent pas nécessaires : voir les deux derniers updates dans la trace.



Hibernate version:
3.03


Mapping documents:

Extrait du mapping de la classe Member :
<many-to-one
name="address"
class="fr.as.poc.model.impl.Address"
cascade="all"
column="ID_ADDRESS"
not-null="true"
unique="true"
/>

<set name="qualifications" cascade="all">
<key column="ID_MEMBER" not-null="true"/>
<one-to-many class="fr.as.poc.model.impl.Qualification"/>
</set>

Extrait du mapping de la classe Address :
<many-to-one
name="country"
class="fr.as.poc.model.impl.Country"
cascade="none"
outer-join="true"
column="ID_COUNTRY"
not-null="true"
lazy="false"
/>

Extrait du mapping de la classe Qualification :
<many-to-one
name="degree"
class="fr.as.poc.model.impl.Degree"
cascade="none"
outer-join="auto"
column="ID_DEGREE"
not-null="true"
/>


Name and version of the database you are using:
JDBC driver: Oracle JDBC driver, version: 9.2.0.1.0


The generated SQL (show_sql=true):

15:06:21,827 | DEBUG | SQL:311 | select degree0_.ID_DEGREE as ID1_0_, degree0_.NAME as NAME2_0_ from T_DEGREE degree0_ where degree0_.ID_DEGREE=?
15:06:22,337 | DEBUG | SQL:311 | select degree0_.ID_DEGREE as ID1_0_, degree0_.NAME as NAME2_0_ from T_DEGREE degree0_ where degree0_.ID_DEGREE=?
15:06:22,748 | DEBUG | SQL:311 | select country0_.ID_COUNTRY as ID1_0_, country0_.NAME as NAME1_0_ from T_COUNTRY country0_ where country0_.ID_COUNTRY=?
15:06:23,269 | DEBUG | SQL:311 | select seq_id_member.nextval from dual
15:06:23,569 | DEBUG | SQL:311 | select seq_id_address.nextval from dual
15:06:23,779 | DEBUG | SQL:311 | select country_.ID_COUNTRY, country_.NAME as NAME1_ from T_COUNTRY country_ where country_.ID_COUNTRY=?
15:06:23,930 | DEBUG | SQL:311 | select seq_id_qualification.nextval from dual
15:06:24,080 | DEBUG | SQL:311 | select seq_id_qualification.nextval from dual
15:06:24,240 | DEBUG | SQL:311 | insert into T_ADDRESS (ADDRESS_1, ADDRESS_2, ADDRESS_3, ADDRESS_4, ZIPCODE, CITY, ID_COUNTRY, EMAIL, FAX_NUMBER, PHONE_NUMBER, ID_ADDRESS) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
15:06:24,320 | DEBUG | SQL:311 | insert into T_MEMBER (FIRSTNAME, LASTNAME, ID_ADDRESS, ID_MEMBER) values (?, ?, ?, ?)
15:06:24,390 | DEBUG | SQL:311 | insert into T_QUALIFICATION (ID_DEGREE, YEAR, ID_MEMBER, ID_QUALIFICATION) values (?, ?, ?, ?)
15:06:24,430 | DEBUG | SQL:311 | insert into T_QUALIFICATION (ID_DEGREE, YEAR, ID_MEMBER, ID_QUALIFICATION) values (?, ?, ?, ?)
15:06:24,480 | DEBUG | SQL:311 | update T_QUALIFICATION set ID_MEMBER=? where ID_QUALIFICATION=?
15:06:24,500 | DEBUG | SQL:311 | update T_QUALIFICATION set ID_MEMBER=? where ID_QUALIFICATION=?


Debug level Hibernate log excerpt:

AbstractCollectionPersister:474 | Static SQL for collection: fr.as.poc.model.impl.Member.qualifications
AbstractCollectionPersister:475 | Row insert: update T_QUALIFICATION set ID_MEMBER=? where ID_QUALIFICATION=?
AbstractCollectionPersister:477 | Row delete: update T_QUALIFICATION set ID_MEMBER=null where ID_MEMBER=? and ID_QUALIFICATION=?


Je ne comprends pas la raison d'être des deux derniers update. Pourquoi attribuer un ID_MEMBER aux deux lignes de la table T_QUALIFICATION alors que l'ID a déjà été attribué lors des INSERT ? Si j'avais rempli mon set avec 50 qualifications j'aurais eu 50 updates.

Et les je ne comprends pas les deux dernières lignes du log. Un 'row delete' se traduirait par une requête SQL UPDATE alors que lorsque j'appelle session.delete(member) c'est bien un DELETE qui est exécuté. Quant au 'row insert', il se matérialise bien par une requête UPDATE, c'est bien le problème.

Je n'ai pas encore trouvé de réponse sur la doc/faq/forum,

Merci pour votre aide.

A+


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 15, 2005 11:14 am 
Regular
Regular

Joined: Tue May 03, 2005 8:19 am
Posts: 53
Location: Paris
Quote:
<set name="qualifications" cascade="all">
<key column="ID_MEMBER" not-null="true"/>
<one-to-many class="fr.as.poc.model.impl.Qualification"/>
</set>

passe l'attribut cascade à all-delete-orphan pour la suppression des Qualification, soit :
Code:
<set name="qualifications" cascade="all,delete-orphan">
<key column="ID_MEMBER" not-null="true"/>
<one-to-many class="fr.as.poc.model.impl.Qualification"/>
</set>


voir mon post http://forum.hibernate.org/viewtopic.php?t=943579


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 22, 2005 6:02 am 
Newbie

Joined: Wed Jun 15, 2005 9:18 am
Posts: 11
Bonjour,

Merci pour votre réponse, mais la valeur all-delete-orphan pour l'attribut cascade ne change pas les requête qui sont executés.

L'attribut not-null="true" dans la déclaration <key column="ID_MEMBER" not-null="true"/> permet justement à Hibernate d'exécuter les requêtes dans le bon ordre.

not-null="false"
=> Hibernate génère la requête suivante : insert into T_QUALIFICATION (ID_DEGREE, YEAR, ID_QUALIFICATION) values (?, ?, ?) : erreur (violation de la contrainte qui veut que la colonne ID_Member de la table T_Qualification ne peut pas être nulle)

not-null="true"
=> Hibernate génère la requête suivante : insert into T_QUALIFICATION (ID_DEGREE, YEAR, ID_MEMBER, ID_QUALIFICATION) values (?, ?, ?, ?) : pas d'erreur. Mais j'ai quand même les deux updates à la fin qui ne servent à rien.

Merci,

A+


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 22, 2005 8:00 am 
Regular
Regular

Joined: Tue May 03, 2005 8:19 am
Posts: 53
Location: Paris
Je suis tout à fait d'accord avec toi pour l'attribut not-null.

Par contre je pensais que all-delete-orphan répondait à ceci:
Quote:
Et les je ne comprends pas les deux dernières lignes du log. Un 'row delete' se traduirait par une requête SQL UPDATE alors que lorsque j'appelle session.delete(member) c'est bien un DELETE qui est exécuté. Quant au 'row insert', il se matérialise bien par une requête UPDATE, c'est bien le problème.


En regardant le test unitaire org.hibernate.test.orphan,
Code:
<hibernate-mapping package="org.hibernate.test.orphan">
   <class name="Product">
      <id name="name"/>
      <set name="parts" cascade="all,delete-orphan" fetch="join">
         <key column="productName" not-null="true"/>
         <one-to-many class="Part"/>
      </set>
   </class>
   
   <class name="Part">
      <id name="name"/>
      <property name="description" not-null="true"/>
   </class>
</hibernate-mapping>


Je ne vois pas d'update sur les objets Product, mais c'est surement à cause d'un autre paramétrage.
Code:
DEBUG BasicEntityPersister:2220 - Static SQL for entity: org.hibernate.test.orphan.Part
DEBUG BasicEntityPersister:2222 -  Version select: select name from Part where name =?
DEBUG BasicEntityPersister:2223 -  Snapshot select: select part_.name, part_.description as descript2_1_ from Part part_ where part_.name=?
DEBUG BasicEntityPersister:2225 -  Insert 0: insert into Part (description, productName, name) values (?, ?, ?)
DEBUG BasicEntityPersister:2226 -  Update 0: update Part set description=? where name=?
DEBUG BasicEntityPersister:2227 -  Delete 0: delete from Part where name=?
DEBUG CacheFactory:39 - instantiating cache region: hibernate.test.org.hibernate.test.orphan.Product usage strategy: nonstrict-read-write
DEBUG BasicEntityPersister:2220 - Static SQL for entity: org.hibernate.test.orphan.Product
DEBUG BasicEntityPersister:2222 -  Version select: select name from Product where name =?
DEBUG BasicEntityPersister:2223 -  Snapshot select: select product_.name from Product product_ where product_.name=?
DEBUG BasicEntityPersister:2225 -  Insert 0: insert into Product (name) values (?)
DEBUG BasicEntityPersister:2226 -  Update 0: null
DEBUG BasicEntityPersister:2227 -  Delete 0: delete from Product where name=?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.