nhibernate : one-to-many

nhibernate : one-to-many - C#/.NET managed - Programmation

Marsh Posté le 08-08-2008 à 17:00:36    

salut,  
 
J'ai un soucis avec nhibernate et le mapping many to one.
 

Citation :

"Le nom de colonne 'IDSOCIETE' apparaît plusieurs fois dans la liste des colonnes de résultat"


 
j'ai une table news et une table société.
dans la table news, j'ai une clé étrangère vers société.
 
avec cette ligne cela fonctionne :  
<many-to-one name="Societe" class="Webmain.Common.Modules.Societe.Societe, Webmain" column="IDSOCIETE" cascade="all" />
 
je récupère bien les éléments de la société.
cependant, cela ne fonctionne qu'en lecture. si je jeux insérer dans la base cela ne fonctionne plus étant donné que j'ai 2x la colonne IDSOCIETE mappée.
<property name="IdSociete" column="IDSOCIETE" not-null="true" type="System.Int32" access="property" />
 
or, j'ai besoin de l'idSociete pour faire mes update.  
 
comment faire ?
 
merci d'avance


Message édité par twisted le 08-08-2008 à 17:00:47
Reply

Marsh Posté le 08-08-2008 à 17:00:36   

Reply

Marsh Posté le 11-08-2008 à 21:56:45    

aidez-moi. je débute avec nhibernate et je ne vois vraiment pas comment faire..
de plus, je dois rendre le projet dans peu de temps  :sweat:  
 
s'il vous plait

Reply

Marsh Posté le 11-08-2008 à 22:03:43    

Tu peux mettre tes fichiers xml en entier parceque la j'ai du mal a comprendre ce que tu essaie de faire.

Reply

Marsh Posté le 11-08-2008 à 22:40:17    

ok. alors voici mes deux fichiers xml :
 

Code :
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" default-access="nosetter.camelcase">
  3.     <class name="Webmain.Common.Modules.Utilisateur.Utilisateur, Webmain" table="UTILISATEURS">
  4.         <id name="IdUtilisateur" column="IDUTILISATEUR" type="System.Int32" access="property">
  5.             <generator class="identity"/>
  6.         </id>
  7.         <property name="IdSociete" column="IDSOCIETE" not-null="true" type="System.Int32" access="property" />
  8.         <property name="Nom" column="NOM" not-null="true" type="System.String" access="property" />
  9.         <property name="Prenom" column="PRENOM" not-null="true" type="System.String" access="property" />
  10.         <property name="Login" column="LOGIN" not-null="true" type="System.String" access="property" />
  11.         <property name="Mdp" column="MDP" not-null="true" type="System.String" access="property" />
  12.         <property name="Email" column="EMAIL" not-null="true" type="System.String" access="property" /> 
  13.         <many-to-one name="Societe" class="Webmain.Common.Modules.Societe.Societe, Webmain" column="IDSOCIETE" cascade="all" />
  14.     </class>
  15. </hibernate-mapping>


 

Code :
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" default-access="nosetter.camelcase">
  3.     <class name="Webmain.Common.Modules.Societe.Societe, Webmain" table="SOCIETES">
  4.         <id name="IdSociete" column="IDSOCIETE" type="System.Int32" access="property">
  5.             <generator class="identity"/>
  6.         </id>
  7.         <property name="RaisonSociale" column="RAISONSOCIALE" not-null="true" type="System.String" access="property" />
  8.     </class>
  9. </hibernate-mapping>


 
cela fonctionne bien si je veux récupérer une valeur.
par exemple si la variable "user" est de type Utilisateur, je peux faire :
user.Login
user.Societe.RaisonSociale
...
 
en revanche quand je veux ajouter un enregistrement dans la base avec Save(), cela ne fonctionne plus.
"Le nom de colonne 'IDSOCIETE' apparaît plusieurs fois dans la liste des colonnes de résultat".
J'imagine que nhibernate ne peut pas mapper le même champ pour 2 propriétés.
 
dans ce cas, comment utiliser mon IDSOCIETE pour pouvoir le mettre à jour ?
 
je te remercie d'avance de ton aide ;)


Message édité par twisted le 11-08-2008 à 22:41:23
Reply

Marsh Posté le 12-08-2008 à 09:59:21    

Je n'ai fait de l'hibernate qu'en java donc je ne peux que t'aider sur le fichier hibernate mais il faudra que tu mette aussi ton code à jour en conséquence.
 
En fait tu demande a hibernate de créer 2 fois la même colonne ce qu'il ne peux pas faire.
Si j'ai bien compris tu veux qu'une société peux avoir plusieurs utilisateurs mais qu'un utilisateur ne peut être associé à qu'une seule société. (d'où le one-to-many / many-to-one)
 
Il te faut donc qu'une seule association one-to-many dans la classe Utilisateur

Code :
  1. <many-to-one name="Societe" class="Webmain.Common.Modules.Societe.Societe, Webmain" column="IDSOCIETE" cascade="all" />


me semble bien
 
Par contre il faut que tu fasse l'association dans l'autre sens dans la classe Societe avec quelque chose qui doit ressembler a cela : (j'utilise set qui correspond au set de java qui est une simple collection, il faut que tu trouve l'équivalent en C#)

Code :
  1. <set name="utilisateurs" inverse="true">
  2.    <key column="IDSOCIETE" />
  3.    <one-to-many class="Webmain.Common.Modules.Utilisateur.Utilisateur, Webmain" />
  4. </set>


 
 
Je n'ai pas très bien compris pourquoi tu veux deux élements ayant le meme nom dans la même classe mais ce n'est pas possible. (le xml d'hinbernate correspond bien à un objet et un objet ne peux avoir plusieurs membres ayant le même nom)


Message édité par h4rold le 12-08-2008 à 10:03:02
Reply

Marsh Posté le 12-08-2008 à 10:07:16    

ok. donc, je récapitule, (dis moi si ce que j'écris est faux) :
 
avec la property Societe dans Utilisateur : je récupère la Société associé à l'utilisateur
avec la property utilisateurs dans Societe : je récupère la liste des utilisateurs de la société
 
tout cela fonctionne  :)  :)  
en revanche pour mettre à jour, je ne peut plus utiliser l'id de la clé étrangère.
j'ai trouvé une solution il y a une heure, ça fonctionne mais ce n'est peut être pas la bonne façon de faire.
 
j'envoie directement l'objet dans la property.
 
je fait :  
 
Utilisateur u = new Utilisateur();
u.Nom = "toto"
u.Societe = maSociete; // maSociete est de type Societe
 
c'ets correct ?

Reply

Marsh Posté le 12-08-2008 à 12:07:50    

twisted a écrit :

ok. donc, je récapitule, (dis moi si ce que j'écris est faux) :
 
avec la property Societe dans Utilisateur : je récupère la Société associé à l'utilisateur
avec la property utilisateurs dans Societe : je récupère la liste des utilisateurs de la société
 
tout cela fonctionne  :)  :)  
en revanche pour mettre à jour, je ne peut plus utiliser l'id de la clé étrangère.
j'ai trouvé une solution il y a une heure, ça fonctionne mais ce n'est peut être pas la bonne façon de faire.
 
j'envoie directement l'objet dans la property.
 
je fait :  
 
Utilisateur u = new Utilisateur();
u.Nom = "toto"
u.Societe = maSociete; // maSociete est de type Societe
 
c'ets correct ?


 
C'est exactement la facon de faire avec Hibernate. Tu as besoin des clefs primaire et étrangeres pour que hibernate puisse les manager dans la base de donnée mais le but est de ne jamais les utiliser dans ton code. (sauf a la rigueur si tu fait du web pour se passer un id entre le client et le serveur / tu as aussi besoin de créer les getter/setters pour que Hibernate puisse les utiliser)
Il faut cependant que maSociete existe et soit déja enregistré dans la base (un Save() )
 
Le but d'hibernate est vraiment de ne plus a se soucier de la base de donnée et de raisonner en objet (en sachant qu'en plus derriere tu n'es pas obligé de mettre une base, tu peux mettre du xml par exemple)


Message édité par h4rold le 12-08-2008 à 12:09:58
Reply

Marsh Posté le 12-08-2008 à 13:54:11    

ok. maintenant tout mon mapping fonctionne.
 
merci beaucoup pour tes explications ;)

Reply

Marsh Posté le 12-08-2008 à 15:43:20    

No prob. Si tu as d'autre problème, je me suis suffisement cassé les dents sur Hibernate pour pouvoir éventuellement te répondre :)

Reply

Marsh Posté le 12-08-2008 à 16:45:03    

h4rold a écrit :

No prob. Si tu as d'autre problème, je me suis suffisement cassé les dents sur Hibernate pour pouvoir éventuellement te répondre :)


 
merci :) ça m'arrange, j'ai un autre problème.
 

Code :
  1. deleted object would be re-saved by cascade (remove deleted object from associations): 1, of class: Webmain.Common.Modules.Societe.Societe


 
d'après ce que j'ai lu sur le net, ce problème apparait lorsqu'on ajoute notamment des relations many-to-one.
 
ma fonction de suppression :
 

Code :
  1. public void deleteOne(object item)
  2.         {
  3.             ITransaction transaction = null;
  4.             try
  5.             {
  6.                 transaction = session.BeginTransaction();
  7.                 session.Delete(item);
  8.                 transaction.Commit();
  9.             }
  10.             catch
  11.             {
  12.                 if (transaction != null)
  13.                     transaction.Rollback();
  14.                 throw;
  15.             }
  16.         }


 
si tu as une idée d'où pourrait venir ce problème.
 
merci d'avance

Reply

Marsh Posté le 12-08-2008 à 16:45:03   

Reply

Marsh Posté le 12-08-2008 à 16:55:28    

twisted a écrit :


 
merci :) ça m'arrange, j'ai un autre problème.
 

Code :
  1. deleted object would be re-saved by cascade (remove deleted object from associations): 1, of class: Webmain.Common.Modules.Societe.Societe


 
d'après ce que j'ai lu sur le net, ce problème apparait lorsqu'on ajoute notamment des relations many-to-one.
 
ma fonction de suppression :
 

Code :
  1. public void deleteOne(object item)
  2.         {
  3.             ITransaction transaction = null;
  4.             try
  5.             {
  6.                 transaction = session.BeginTransaction();
  7.                 session.Delete(item);
  8.                 transaction.Commit();
  9.             }
  10.             catch
  11.             {
  12.                 if (transaction != null)
  13.                     transaction.Rollback();
  14.                 throw;
  15.             }
  16.         }


 
si tu as une idée d'où pourrait venir ce problème.
 
merci d'avance


 
Je pense que le problème vient du fait que dans un one-to-many, 1 instance d'une classe (one) est lié à plusieurs instances d'une autre classe (many). Si tu supprime une instance du one, alors les many seront associés à une instance qui n'existe plus d'où le fait qu'il ne puisse pas la supprimer.
 
En gros tu peux supprimer un utilisateur sans problème (hibernate enlevera l'instance Utilisateur et la supprimera de la collection membre de la classe Societe) mais tu ne peux pas supprimer une société car des utilisateurs existent et sont liés à cette société. (il faut a ce moment la les licensier ;))
 
Je ne suis plus sur mais si tu met un not-null="false" alors l'association ne seras plus obligatoire des utilisateurs a la société. ( un utilisateur pourra ne pas avoir de société)

Reply

Marsh Posté le 12-08-2008 à 18:34:39    

Citation :

Je ne suis plus sur mais si tu met un not-null="false" alors l'association ne seras plus obligatoire des utilisateurs a la société. ( un utilisateur pourra ne pas avoir de société)


 
Un utilisateur doit avoir une société. mon champ idSociete dans la table utilisateur est en not null. avec une contrainte foreign key vers la clé primaire de la table société.
c'est donc normal que j'ai une exception si je veux supprimer une société utilisée par un utilisateur.
 
en revanche, je pense que ce n'est pas normal d'avoir une erreur pour supprimer un utilisateur (personne ne référence sa clé primaire).
 
tu n'as pas d'autres idées?

Reply

Marsh Posté le 12-08-2008 à 21:17:50    

twisted a écrit :

Citation :

Je ne suis plus sur mais si tu met un not-null="false" alors l'association ne seras plus obligatoire des utilisateurs a la société. ( un utilisateur pourra ne pas avoir de société)


 
Un utilisateur doit avoir une société. mon champ idSociete dans la table utilisateur est en not null. avec une contrainte foreign key vers la clé primaire de la table société.
c'est donc normal que j'ai une exception si je veux supprimer une société utilisée par un utilisateur.
 
en revanche, je pense que ce n'est pas normal d'avoir une erreur pour supprimer un utilisateur (personne ne référence sa clé primaire).
 
tu n'as pas d'autres idées?


 
Heu dans la logique si tu veux supprimer un utilisateur tu supprime la référence dans la liste de la société "possédant" cette utilisateur. Ensuite tu commit et ca devrait passer :)

Reply

Marsh Posté le 13-08-2008 à 17:28:19    

Citation :

tu supprime la référence dans la liste de la société "possédant" cette utilisateur


 
je ne comprend ce que tu veux dire par supprimer la référence.
j'ai beau cherché dsl, je vois pas.
tu peux mettre du code java sans problème, je traduirais en c#.

Reply

Marsh Posté le 13-08-2008 à 18:06:00    

Utilisateur u;
...
u.getSociete().getListUtilisateurs.remove(u);
Tu choppe la société correspondant à l'utilisateurs et tu supprime l'utilisateurs de la liste de ses utilisatreurs.

Reply

Marsh Posté le 13-08-2008 à 23:51:24    

j'ai essayé ce que tu dis. en c#, cela donne :
 

Code :
  1. u.Societe.ListeUtilisateurs.Remove(u);


 
mais aucune différence. j'ai toujours la même exception  :(  
 
dans la doc, je ne voit rien à ce sujet. je ne sais plus quoi faire.

Reply

Marsh Posté le 15-08-2008 à 16:34:10    

j'ai résolution mon problème en mettant l'attribut cascade à none sur les many-to-one.
 
en espérant qu'il n'y aura pas d'effets de bord...

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed