-->
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.  [ 8 posts ] 
Author Message
 Post subject: ajout d'une colone sur une table "n-m"
PostPosted: Mon Sep 26, 2005 6:38 am 
Newbie

Joined: Mon Sep 26, 2005 6:20 am
Posts: 6
Bonjour, tous le monde,
je me casse les dents sur un problème pourtant bien documenté.
J'utilise hibernate 3.

J'ai 3 tables, annonce, contact, adresse,
j'ai une relation n-m entre annonce et contact et entre contact et adresse.

Dans cette configuration, aucun problèmes.

Maintenant je veux ajouter dans la table annonce_contact l'id de l'addresse du contact valable pour cette annonce.

Du coup, je dois rendre visible la table annonce_contact, créer une clé composite et ajouter addresse_id.

Ce qui me donne :

<class name="Addresses" table="addresses">
<id name="AddressId" type="java.lang.Integer">
<column name="address_id" length="11" not-null="true" unique="true" sql-type="int" />
<generator class="native" />
</id>
...
</class>
<class name="Ads" table="ads">
<id name="AdId" type="java.lang.Integer">
<column name="ad_id" length="11" not-null="true" unique="true" sql-type="int" />
<generator class="native" />
</id>

<bag name="AdsContacts">
<key column="ad_id"/>
<one-to-many class="AdsContacts"/>
</bag>
...
</class>

<class name="AdsContacts" table="ads_contacts">
<composite-id name="id"
class="AdsContactsId"
>
<key-many-to-one name="Contacts" class="Contacts">
<column name="contact_id" length="11" not-null="false" />
</key-many-to-one>
<key-many-to-one name="Ads" class="Ads">
<column name="ad_id" length="11" not-null="false" />
</key-many-to-one>
</composite-id>

<property name="AddressId" type="java.lang.Integer">
<column name="address_id" length="11" not-null="true" sql-type="int unsigned" />
</property>
</class>

Dans cette configuration, au moment ou je tente de faire le session.save(annonce), apres avoir sauvé l'adresse et le contact
Hibernate me lance le query Hibernate:

insert into ads_contacts (address_id, contact_id, ad_id) values (?, ?, ?)

et du coup l'exception

26 sept. 2005 12:04:55 org.hibernate.util.JDBCExceptionReporter logExceptions
ATTENTION: SQL Error: 1048, SQLState: 23000
26 sept. 2005 12:04:55 org.hibernate.util.JDBCExceptionReporter logExceptions
GRAVE: Column 'ad_id' cannot be null

J'ai tourné le problème dans tous les sens et comparé mon code avec d'autre exemple de clés composites, mais je ne m'en sort pas.

Une idée sur la bienvenue.

J'ai essayé de rester concis mais s'il manque des infos n'hésitez pas à me les demander....
Merci beaucoup pour votre aide.
Julien


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 26, 2005 8:09 am 
Beginner
Beginner

Joined: Tue Jul 05, 2005 4:44 am
Posts: 40
Location: Paris, France
salut julien,

Pour un code un peu plus clair, merci d'utiliser les balises code.

Bon, je pense que ton problème ne se situe pas au niveau de relation n-m entre Contact et Adresse mais plutot entre les relations bi-directionnel entre Contact et ContactAdresse et Adresse et ContactAdresse.

Plus d'info là dessus sur la doc de ref "Hibernate reference documentation, chapter 2".

Si tu galère encore... n'hésite pas en fournissant les classes des modèles ainsi que ton exemple d'insertion (qui montre comment tu lies les classes Contact - ContactAdresse et Adresse-ContactAdresse).

Bon courage !

_________________
Fred


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 26, 2005 10:05 am 
Newbie

Joined: Mon Sep 26, 2005 6:20 am
Posts: 6
Merci pour ta réponse,
au niveau de la relation contacts adresses j'ai une relation many-to-many standard. La mise a jour de la table contacts_adresses se fait correctement.

En regardant ce post http://www.theserverside.com/discussion ... d_id=31850

je suis arrivé à avancer quelque peu. En fait je faisait un save de AdsContacts avant d'avoir fait le save de Ads, ce qui posait un problème vu que l'ad_id n'était pas encore affecté.

Le problème c'est que maintenant, je n'ai plus aucune erreur, l'objet Ad parait complet quand on le regarde dans le debugger, avec sa liste de AdsContacts remplis, qui pointent bien sur le contact, sur l'adress_id et sur l'Ads mais la table ads_contact est totalement ignorée. Il n'y a pas d'insert qui se fait.

Pour rappel :

Adresses.hbm.xml
Code:
<class name="Addresses" table="addresses">
<id name="AddressId" type="java.lang.Integer">
<column name="address_id" length="11" not-null="true" unique="true" sql-type="int" />
<generator class="native" />
</id>
<property
        name="AddressLine1"
        type="java.lang.String"
>
    <column name="address_line_1" not-null="true" sql-type="varchar" />
</property>
...


Ads.hbm.xml
Code:
</class>
<class name="Ads" table="ads">
<id name="AdId" type="java.lang.Integer">
<column name="ad_id" length="11" not-null="true" unique="true" sql-type="int" />
<generator class="native" />
</id>

<bag name="AdsContacts" inverse="true">
<key column="ad_id"/>
<one-to-many class="AdsContacts"/>
</bag>
...
</class>


AdsContacts.hbm.xml
Code:
<class name="AdsContacts" table="ads_contacts">
<composite-id name="id"
class="AdsContactsId"
>
<key-many-to-one name="Ads" class="Ads">
<column name="ad_id" length="11" not-null="false" />
</key-many-to-one>
<key-many-to-one name="Contacts" class="Contacts">
<column name="contact_id" length="11" not-null="false" />
</key-many-to-one>
</composite-id>

<property name="AddressId" type="java.lang.Integer">
<column name="address_id" length="11" not-null="true" sql-type="int unsigned" />
</property>
</class>


AdsMgr.java
Code:

Ads myAd = new Ads();
AdsContacts myAdsContact = new AdsContacts();
Contacts contact = new Contact();

contact.setName("toto");
session.save(contact);

myAdsContact.getId().setContacts(contact);
myAdsContact.getId().setAds(myAd);
myAdsContact.setAddressId(contact.getAddresses().get(0).getAddressId());

session.save(myAd);



J'ai bien les tables Ads , Contacts, Addresses et Contacts_Addresses remplies, mais Ads_Contacts reste désespérément vide.

J'ai aussi tenté un session.save() de chaque AdsContacts après le save de myAd mais ca ne change rien. Je ne vois jamais passé de sql dans le log avec un insert dans ads_contacts.

Vous voyez un autre moyen ?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 27, 2005 1:54 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Code:
Ads myAd = new Ads();
Contacts contact = new Contact();
contact.setName("toto");
session.save(contact);
session.save(myAd);

AdsContacts myAdsContact = new AdsContacts();
myAdsContact.getId().setContacts(contact);
myAdsContact.getId().setAds(myAd);
myAdsContact.setAddressId(contact.getAddresses().get(0).getAddressId());
session.save(myAdsContact);


1. session.save(myAdsContact); est necessaire parce qu'il n'y a aucuce cascade de définie.
2. que fait getId() exactement, comme se fait-il qu'il ne faille pas initialiser AdsContactId, essaye en intialisant cela à la main au lieu de le faire dans le code de l'objet lui même.
3. quelle est l'implémentation equals()/hashCode() de AdsContactId. Elle est nécessaire.

si tout cela ne fonctionne pas, il faut montrer les logs, mais tu devrais déjà t'en sortir avec 1. 2. 3.

4. not-null=false pour une colonne de PK n'a pas de sens

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 28, 2005 2:42 am 
Newbie

Joined: Mon Sep 26, 2005 6:20 am
Posts: 6
Merci pour ta réponse, ca à l'air de changer le comportement.
J'ai maintenant une exception NullPointerException au niveau du saveOrUpdate(myAdsContact)

Code:
java.lang.NullPointerException
   at org.hibernate.type.AbstractType.getHashCode(AbstractType.java:111)
   at org.hibernate.type.AbstractType.getHashCode(AbstractType.java:119)
   at org.hibernate.type.EntityType.getHashCode(EntityType.java:378)
   at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:162)
   at org.hibernate.engine.EntityKey.getHashCode(EntityKey.java:68)
   at org.hibernate.engine.EntityKey.<init>(EntityKey.java:41)
   at org.hibernate.engine.PersistenceContext.getDatabaseSnapshot(PersistenceContext.java:296)
   at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:189)
   at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:409)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:82)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:468)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:463)
   at consultas.adspider.objectmodel.business.AdsMgr.createAd(AdsMgr.java:299)



Ci-dessous le code des fonction equal et hashcode de AdsContactsId. j'ai aussi ajouté les equal et hascode dans toutes les classes mappées.

Code:
/**
    * @see java.lang.Object#equals(Object)
    */
   public boolean equals(Object object) {
      if (!(object instanceof AdsContactsId)) {
         return false;
      }
      AdsContactsId rhs = (AdsContactsId) object;
      return new EqualsBuilder().appendSuper(super.equals(object)).append(
            this.Contacts, rhs.Contacts).append(this.Ads, rhs.Ads)
            .isEquals();
   }
   
   /**
    * @see java.lang.Object#hashCode()
    */
   public int hashCode() {
      return new HashCodeBuilder(2111336019, 437687809).appendSuper(
            super.hashCode()).append(this.Contacts).append(this.Ads)
            .toHashCode();
   }


D'après ce que je vois dans le debugger, la seule valeur "null" que j'ai dans mon objet c'est le adId, qui n'est pas encore créé.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 28, 2005 3:45 am 
Beginner
Beginner

Joined: Tue Jul 05, 2005 4:44 am
Posts: 40
Location: Paris, France
salut,

je connais pas HashCodeBuilder mais est ce que tu ne devrait pas tester rh ?

Code:
/**
    * @see java.lang.Object#equals(Object)
    */
   public boolean equals(Object object) {
      if (!(object instanceof AdsContactsId)) {
         return false;
      }
      AdsContactsId rhs = (AdsContactsId) object;
      EqualsBuilder builder = new EqualsBuilder();
      builder.appendSuper(super.equals(object));
      if (rhs != null) {
            builder.append(this.Contacts, rhs.Contacts).append(this.Ads, rhs.Ads);
      }
      return builder.isEquals();
   }

_________________
Fred


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 28, 2005 6:43 am 
Newbie

Joined: Mon Sep 26, 2005 6:20 am
Posts: 6
pour simplifier, j'ai repris le code du hashcode et du equal générés par le plugin Hibernate de eclipse :
Code:
   public boolean equals(Object other) {
    if ( (this == other ) ) return true;
    if ( (other == null ) ) return false;
    if ( !(other instanceof AdsContactsId) ) return false;
    AdsContactsId castOther = ( AdsContactsId ) other;
   
    return (this.getContacts()==castOther.getContacts()) || (this.getContacts()==null ? false : (castOther.getContacts()==null ? false : this.getContacts().equals(castOther.getContacts())))
&& (this.getAds()==castOther.getAds()) || (this.getAds()==null ? false : (castOther.getAds()==null ? false : this.getAds().equals(castOther.getAds())));
}

public int hashCode() {
    int result = 17;
   
    result = 37 * result + this.getContacts().hashCode();
    result = 37 * result + this.getAds().hashCode();
    return result;
}


j'arrive toujour à ca :
Code:
java.lang.NullPointerException
   at org.hibernate.type.AbstractType.getHashCode(AbstractType.java:111)
   at org.hibernate.type.AbstractType.getHashCode(AbstractType.java:119)
   at org.hibernate.type.EntityType.getHashCode(EntityType.java:378)
   at org.hibernate.type.ComponentType.getHashCode(ComponentType.java:162)
   at org.hibernate.engine.EntityKey.getHashCode(EntityKey.java:68)
   at org.hibernate.engine.EntityKey.<init>(EntityKey.java:41)
   at org.hibernate.engine.PersistenceContext.getDatabaseSnapshot(PersistenceContext.java:296)
   at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:189)
   at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:409)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:82)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:69)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:468)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:463)
   at consultas.adspider.objectmodel.business.AdsMgr.createAd(AdsMgr.java:299)


Pour poursuivre avec emmanuel :
j'ai fais le point 1,

pour le point 2:
getId() retourne simplement l'objet AdsContactsId qui contient les 2 propriétés Ads et Contacts

le point 3:
c'est fait aussi.

C'est certainement un truc tout simple qui me manque mais c'est mon premier projet sur hibernate et là je cale.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 28, 2005 10:36 am 
Newbie

Joined: Mon Sep 26, 2005 6:20 am
Posts: 6
Merci a tous..
j'ai enfin résolu mon problème.

j'ai utilisé un autre approche, encore plus simple et qui répond mieux a mon besoin. Le <composite-element>

D'autres part, certainement que ca avait fonctionné a un moment ou a un autre mais je me suis fais avoir par le fait que les tables "satellites" comme ads_contacts ne sont gérées qu'au flush ou au commit.

Je ne voyais pas passer le sql dans le log, parce qu'il fallait attendre que le batch de mise a jour s'execute... au commit qui se fait toutes les 10 insertions chez moi.

Merci de votre aide et désolé du dérangement.
Julien


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 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.