IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Hibernate Java Discussion :

ID-generator et many-to-one


Sujet :

Hibernate Java

  1. #1
    Membre à l'essai
    Inscrit en
    Septembre 2007
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Septembre 2007
    Messages : 21
    Points : 14
    Points
    14
    Par défaut ID-generator et many-to-one
    Bonjour,
    J'ai un probleme avec la génération des clés dans une relation many-to-one. Je m'explique:
    J'ai une objet Client auqu'elle j'ai associé une liste d'objet contactsClient
    J'ai definie mon propre generateur pour les identifiants de ces deux classes.
    L'identifiant des ContactClient s'obtient de facon incremental sur le numero de Client (voir code).
    Mais lorsque j'enregistre un client avec deux contacts, il genere la même clé pour les deux contacts ce qui cause une violation de contrainte unique

    - Fichiers HBM.XML
    =============
    Client :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <hibernate-mapping package="com.srv.crm">
    	<class
    		name="Client"
    		table="NOYP_CLIENT"
    	>
    		<meta attribute="sync-DAO">false</meta>
    		<id
    			name="id"
    			type="string"
    			column="ID"
    		>
    			<generator class="com.hibernate.IardGenerator"/>
    		</id>
     
    		<property
    			name="code"
    			column="CODE_CLIENT"
    			type="string"
    			not-null="true"
    			length="25"
    		/>
     
     		<set name="contacts" inverse="true" cascade="all, delete-orphan">
    			<key column="ID_CLI"/>
    			<one-to-many class="ContactClient"/>
    		</set>
    	</class>	
    </hibernate-mapping>
    ContactClient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <hibernate-mapping package="com.srv.crm">
    	<class
    		name="ContactClient"
    		table="NOYP_CONTACT_CLIENT"
    	>
    		<meta attribute="sync-DAO">false</meta>
    		<id
    			name="id"
    			type="string"
    			column="CODE_CONTACTCLI"
    		>
    			<generator class="com.srv.hibernate.IardGenerator"/>
    		</id>		
    		<property
    			name="nomContact"
    			column="NOM_CONTACTCLI"
    			type="string"
    			not-null="true"
    			length="64"
    		/>				
    		<many-to-one
    			name="client"
    				class="Client"
    				column="ID_CLI"
    			not-null="true"
    		>
    		</many-to-one>
     
    	</class>	
    </hibernate-mapping>
    -Codes sources IDGenerator
    =====================

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
     
     package com.srv.hibernate;
     
    import java.io.Serializable;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java. Properties;
    import org.hibernate.HibernateException;
    import org.hibernate.MappingException;
    import org.hibernate.dialect.Dialect;
    import org.hibernate.engine.SessionImplementor;
    import org.hibernate.exception.JDBCExceptionHelper;
    import org.hibernate.id.Configurable;
    import org.hibernate.id.IdentifierGenerator;
    import org.hibernate.id.PersistentIdentifierGenerator;
    import org.hibernate.jdbc.Batcher;
    import org.hibernate.mapping.Table;
    import org.hibernate.type.Type;
    import org.hibernate. StringHelper;
     
    public class IardGenerator implements IdentifierGenerator, Configurable {
    	private String next;
     
    	private String sql;// = "select max(ID) from NOYP_BRANCHE";
     
    	private String prefixe = null;
     
    	private int tail = 0;
     
    	private String col;
     
    	public synchronized Serializable generate(SessionImplementor session,
    			Object object) throws HibernateException {
    		String[] tmp =  getPrefixe(object).split("#");
    		prefixe = tmp[0];
    		if (tmp.length > 1)
    			tail = Integer.parseInt(tmp[1]);
    		if (sql != null) {
    			getNext(session);
    		}
    		System.err.println("GENERATION de l'object " + object.toString()
    				+ " cle=" + next);
    		return next;
    	}
     
    	public void configure(Type type, Properties params, Dialect dialect)
    			throws MappingException {
    		// obtention du nom de la table
    		String tableList = params.getProperty("tables");
    		if (tableList == null)
    			tableList = params
    					.getProperty(PersistentIdentifierGenerator.TABLES);
    		// liste de toutes les tables
    		String[] tables = StringHelper.split(", ", tableList);
    		// recherche de la colonne
    		String column = params.getProperty("column");
    		if (column == null)
    			column = params.getProperty(PersistentIdentifierGenerator.PK);
    		// recherche du schema
    		String schema = params
    				.getProperty(PersistentIdentifierGenerator.SCHEMA);
    		// recherche du catalogue
    		String catalog = params
    				.getProperty(PersistentIdentifierGenerator.CATALOG);
     
    		StringBuffer buf = new StringBuffer();
    		for (int i = 0; i < tables.length; i++) {
    			if (tables.length > 1) {
    				buf.append("select ").append(column).append(" from ");
    			}
    			buf.append(Table.qualify(catalog, schema, tables[i]));
    			if (i < tables.length - 1)
    				buf.append(" union ");
    		}
    		if (tables.length > 1) {
    			buf.insert(0, "( ").append(" ) ids_");
    			column = "ids_." + column;
    		}
     
    		sql = "select max(" + column + ") from " + buf.toString();
    		col = column;
    		System.err.println("REQUETTE= " + sql);
    	}
     
    	private void getNext(SessionImplementor session) {
    		try {
    			StringBuffer buf = new StringBuffer();
    			buf.append(sql).append(" where ").append(col).append(" like '").append(prefixe).append("%'");
    			System.err.println("REQUETTE A EXE = " + buf.toString());
    			Batcher bc = session.getBatcher();
    			PreparedStatement st = bc.prepareSelectStatement(
    					buf.toString());
    			try {
    				ResultSet rs = bc.getResultSet(st);//st.executeQuery();
    				try {
    					if (rs.next()) {
    						// next = rs.getLong(1) + 1;
    						try {
    							String ret = rs.getString(1);							
    							long val = Long.parseLong(ret.substring(ret.indexOf(prefixe)+prefixe.length()));
    							val++;
    							next = prefixe +  completer(tail, val);
    						} catch (Exception e) {
    							next = prefixe +  completer(tail, 1);
    						}
    						if (rs.wasNull()) {
    							next = prefixe + completer(tail, 1);
    						}
    					} else {
    						next = prefixe + completer(tail, 1);
    					}
    					// sql = null;
    					// log.debug("first free id: " + next);
    				} finally {
    					rs.close();
    				}
    			} finally {
    				session.getBatcher().closeStatement(st);
    			}
     
    		} catch (SQLException sqle) {
    			throw JDBCExceptionHelper.convert(session.getFactory()
    					.getSQLExceptionConverter(), sqle,
    					"could not fetch initial value for increment generator",
    					sql);
    		}
    	}
     
    	public static String completer(int tail,long val) {
    		System.err.println("ON COMPLETTE= "+val);
    		StringBuffer buf = new StringBuffer();
    		//buf.append(patern);
    		buf.append("0000000000000000000").append(Long.toString(val));
    		buf.substring(buf.length() - tail, buf.length());
    		return buf.substring(buf.length() - tail, buf.length());
    	}
    	public static String getPrefixe(Object obj){		
    		if(obj instanceof Client){
    			return "CLI#10";
    		}
    		if(obj instanceof ContactClient){
    			StringBuffer buf = new StringBuffer();
    			buf.append(((ContactClient)obj).getClient()
    					.getId()).append("#2");
    			return buf.toString();
    		}
    		return "0#0";
    	}
     
    }
    MErci de vos aides

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    Dans ton générateur, tu fait un select max(ID) pour récupérer un nouvel identifiant (max(ID)+1) mais tu ne fait pas d'update pour changer ce max(ID). Résultat, à l'appel suivant, il est toujours le même! A toi de mettre à jour ton compteur correctement pour qu'il soit correct à l'appel suivant.

  3. #3
    Membre à l'essai
    Inscrit en
    Septembre 2007
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Septembre 2007
    Messages : 21
    Points : 14
    Points
    14
    Par défaut Et les collection MAny-to-one
    merci deja tchize_ pour ta reponse.
    Mais mon pb se pose au niveau des collection many-to-one.
    puisque je fait une save unique de mon objet Client avec toute ses collections.
    CE qui fait que c'est hibernate qui se charge de generer les id pr les objets ContactClient.
    Avec un seul objet ContactClient il n'y a pas de probleme mais si je positionne plusieurs objets ContactClient il se pose mon pb.

    Dans le cas ou je fait un save unique de mon objet Client comment faire donc les update apres chaque ContactClient?

  4. #4
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    d'apres ton mqpping hibernate, tu utilise ton propre generateur pour tes contactClient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <class
    		name="ContactClient"
    		table="NOYP_CONTACT_CLIENT"
    	>
    		<meta attribute="sync-DAO">false</meta>
    		<id
    			name="id"
    			type="string"
    			column="CODE_CONTACTCLI"
    		>
    			<generator class="com.srv.hibernate.IardGenerator"/>
    Quand tu va sauver tes client, ton générateur va générer plein de fois le meme id et hibernate va foirer la sauvegarde puisque çà correspond pas la structure SQL


    Si tu me crois pas, met un System.out.println dans ton générateur qui affiche ce qu"il retourne

  5. #5
    Membre à l'essai
    Inscrit en
    Septembre 2007
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Septembre 2007
    Messages : 21
    Points : 14
    Points
    14
    Par défaut A quoi sert donc l'attribut cascade?
    Justement tu as saisie mon pb! mon generateur genere toujours le meme identifiant lorsque j'enregistre unc client qui a plusieurs contact.
    A quoi sert donc l'attibut cascade si je dois moi meme me charger de faire des saves explicite pour chaque contact

    Session s = ...;
    s.save(Client);
    s.save(contact1);
    s.save(contact2)

    au lieu de faire uniquement
    s.save(Client);

    Je pense que mon probleme se situe au niveau de mon generateur!
    Il recherche la prochaine valeur dans la BD et non dans la session courante.
    De plus le generateur est appelé dynamiquement pat hibernate, je n'ai donc plus le controle pour positionner le Id et faire un save.

    A moins que je ne change le generateur de mes contacts a "assigned" et que je me charge de faire tout le boulot avant de save. Mais cela me pose un probleme de généricite, je devrais donc faire cela pour toutes mes association de ce type!

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    ton problème c'est le concept meme de ton générateur qui est foireux, si je lit bien, il prend la table, prend l'élément le plus grand coté ID et rajoute plus un, çà va te poser plusieurs problèmes

    1) comme tu l'a déjà constater, tu ne peux pas générer plusieurs id sans sauver entre deux (c'est pas un problème de session c'est un problème que hibernate, quand il a besoin d'un id, ne va pas pas nécessairement l'écrire immédiatement après dans la db)

    2) si t'as 2 session en // elle vont aussi générer le même id

    Conclusion, change le design de ton générateur. Le générateur doit êter capable de retourner des clés unique, dans ton cas, c'est pas le cas

Discussions similaires

  1. Réponses: 2
    Dernier message: 17/07/2006, 14h45
  2. [Hibernate]POJO et many-to-one
    Par azpublic dans le forum Hibernate
    Réponses: 3
    Dernier message: 13/07/2006, 15h00
  3. html:select et hibernate many-to-one
    Par davdou dans le forum Struts 1
    Réponses: 1
    Dernier message: 05/07/2006, 14h56
  4. Hibernate : suppression sur relation many to one
    Par taf dans le forum Hibernate
    Réponses: 1
    Dernier message: 23/05/2006, 13h08
  5. [hibernate] "many-to-one"
    Par mehdi_swatch dans le forum Hibernate
    Réponses: 26
    Dernier message: 12/05/2006, 20h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo