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
:cry:
- Fichiers HBM.XML
=============
Client :
Code:
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:
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:
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
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?
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!:bug: