-->
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.  [ 11 posts ] 
Author Message
 Post subject: Mapping complexe d'une propriété sur plusieurs tuples
PostPosted: Fri Sep 09, 2005 5:45 am 
Beginner
Beginner

Joined: Fri Sep 09, 2005 5:16 am
Posts: 22
Bonjour,

je suis en phase d'évaluation d'hibernate, et je n'arrive pas à trouver de réponse à un problème de mapping relativement complexe dont voici le contexte :

J'ai une table qui sert à stocker du texte car nos BD ne supportent pas CLOB ou BLOB. Nous devons uniquement utiliser les types simples.
Cette table contient les colonnes
ID (pk)
ORDER (numéro d'ordre de l'enreg)
TXT (texte de l'enreg)

Cette table est alimentée en tronçonnant les chaines texte en portions de 250 caractères et en indiçant chaque tronçon avec la colonne ORDER histoire de pouvoir reconstituer correctement la chaine de caractères.

Les tables référençant cette table de texte le font en utilisant une FK sur cette table de texte.
Pour reconstituer la chaine il faut donc faire un aggrégat de plusieurs tuples.

Ce que je voudrais pouvoir faire c'est donc mapper le contenu de cette table en une propriété de mes classes.

Hibernate permet-il un tel mapping ?

Merci bcp pour vos réponses


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 09, 2005 6:08 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
tu doit pouvoir utiliser formula="(mon subselect)" pour ça.
Voire un UserType

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 09, 2005 6:08 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
en tous cas avec un autre ORM, ca ne va pas être facile ;-)

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 09, 2005 8:04 am 
Beginner
Beginner

Joined: Fri Sep 09, 2005 5:16 am
Posts: 22
emmanuel wrote:
tu doit pouvoir utiliser formula="(mon subselect)" pour ça.
Voire un UserType


Merci pour ta réponse.
Je ne connaissais pas les formula. Mais effectivement je devrais pouvoir m'en sortir avec ça.
Cependant je prefererais pouvoir utiliser un UserType qui présente l'avantage d'être réutilisable. Mais je ne trouve pas d'exemple et j'avoue ne pas trouver comment écrire un user type dans mon cas...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 09, 2005 8:33 am 
Beginner
Beginner

Joined: Fri Sep 09, 2005 5:16 am
Posts: 22
Petite question à propos des formula :
Est ce que hibernate sait gérer la persitence (update/insert) d'une propriété mappée par une formula ?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Sep 09, 2005 10:28 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Non il te faut un usertype pour cela.
A partir d'un UserType, tu peux accéder à la connexion et de là, faire ce que tu veux (même si la plupart du temps, les gens n'utilisent que le statement en cours).

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 11:05 am 
Beginner
Beginner

Joined: Fri Sep 09, 2005 5:16 am
Posts: 22
dans la méthode nullSafeGet d'un UserType, le ResultSet est-il obtenu avec un "select * ... " ou bien en fonction du mapping défini ?

Je pose cette question toujours en rapport avec mon problème de mapping qui revient à masquer des colonnes de ma table par une propriété valorisée en fonction du résultat d'une issue d'une jointure.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 5:58 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
En fonction du mapping. Mais en l'occurence tu ne l'utiliseras pas.
Les UserType peuvent avoir des paramètres en entrée (via le mapping) et l'interface ParameteriedType (regarde la doc). Tu injecteras les infos dont tu as besoin grace à ça.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 6:03 am 
Beginner
Beginner

Joined: Fri Sep 09, 2005 5:16 am
Posts: 22
emmanuel wrote:
En fonction du mapping. Mais en l'occurence tu ne l'utiliseras pas.
Les UserType peuvent avoir des paramètres en entrée (via le mapping) et l'interface ParameteriedType (regarde la doc). Tu injecteras les infos dont tu as besoin grace à ça.


Ok, mais est ce que je peux au moins utiliser le ResultSet de nullSafeGet afin de récupérer l'id de mon entité ? (Utile pour récupérer l'id du texte référencé par mon entité)

... Et dans le même temps, comment vais je pouvoir implémenter nullSafeSet ? Je n'ai aucun moyen apparent de connaitre l'id de mon entité (entre autres problèmes : l'entité n'ayant pas encore été mise à jour en base, comment pourrais-je me permettre de définir la valeur de ma FK sur les textes...)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 20, 2005 9:04 am 
Beginner
Beginner

Joined: Fri Sep 09, 2005 5:16 am
Posts: 22
Ok, à question stupide, pas de réponse... ; )

Un petit peu de temps s'est écoulé, j'espère avoir compris et assimilé un peu plus de chose.

Pour résoudre mon pb j'ai créer une nouvelle classe Text avec un user type associé : TextUserType.
Je ne pense pas avoir la possibilité de me passer d'un type spécial étant donné que j'ai besoin de l'id du texte que je manipule.

Je suis entrain de débugger la methode nullSafeSet.
En paramètre de cette methode j'ai une instance de Text à laquelle je "sette" l'id car il est non défini lors d'un insert...
Cependant, cela n'est pas reporté au niveau de l'instance que je manipule dans mon programme de test. Une copie à due être effectuée par hibernate. Que faut il faire ? Est il invalide de modifier l'instance de l'objet valeur ?

ps : la méthode isMutable() retourne "true"


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 20, 2005 12:54 pm 
Beginner
Beginner

Joined: Fri Sep 09, 2005 5:16 am
Posts: 22
Je re-précise mon cas :

J'ai par exemple une table TEXT_HOLDER avec les colonnes ID (number), NAME (varchar), I_TXT (number) ; ID étant la pk.
Et une table TXT avec les colonnes I_TXT(number), TXT_ORDER(number), TXT_VALUE(varchar de 250) ; I_TXT et ORDER formant la pk.
Cette table TXT contient des tronçons de texte qui sont réassemblés le cas échéant ; Le texte associé à un TEXT_HOLDER sont tronçonnés (en 250 caractères) et insérés dans la table TXT.

TEXT_HOLDER référence donc la table TXT via sa colonne I_TXT

Dans l'idéal j'aimerais avoir une classe TextHolder qui ressemble à cela :
public class TextHolder
{
private Long mId;
private String mName;
private String mSomeText;
...
}

malheureusement je ne crois pas que cela soit possible...

J'ai donc une classe TextHolder :
Code:
public class TextHolder
{
     private Long mId;
     private String mName;
     private Text mSomeText;

     ...
}


J'ai également la classe Text :
Code:
public class Text
{
     private Long mTextId;
     private String mString;
   
     ...
}


avec l'implementation UserType qui va avec :
Code:
public class TextUserType implements UserType, ParameterizedType
{
    public Object nullSafeGet(ResultSet pRs, String[] pNames, Object pOwner) throws HibernateException, SQLException
   {
        long textId = pRs.getLong(getTextIdColumnName());
        if (pRs.wasNull())
            return null;
      
        StringBuffer fullText = new StringBuffer();
       
        Connection conn = pRs.getStatement().getConnection();
        PreparedStatement stmt = conn.prepareStatement("select * from TXT where I_TXT=? order by TXT_ORDER");
        stmt.setLong(0, textId);
        ResultSet rs = stmt.executeQuery();
        while (rs.next())
        {
             fullText.append(rs.getString("TXT_VALUE"));
        }
        return new SnpsText(new Long(textId), fullText.toString());
   }

   private String getTextIdColumnName()
   {
       return mParameters.getProperty(TEXT_ID_COLUMN_NAME);
   }

   public void nullSafeSet(PreparedStatement pSt, Object pValue, int pIndex) throws HibernateException, SQLException
   {
       SnpsText text = (SnpsText)pValue;
       Connection conn = pSt.getConnection();
       PreparedStatement stmt = null;
      
       if (text.getTextId() == null)
       {
   //obtention d'un nouvel identifiant de text
   stmt = conn.prepareStatement("select max(I_TXT) from TXT");
   ResultSet rs = stmt.executeQuery();
   try
   {            
         if (rs.next())
         {
             long newId = rs.getLong(1);
             [b]text.setTextId(new Long(newId + 1));[/b]
         }
         else
         {
             throw new HibernateException("Unable to define an ID for text");
          }         
   }
   finally
   {
       rs.close();
       stmt.close();
   }
        }
        else
        {         
   //suppression du text existant
   try
   {
        stmt = conn.prepareStatement("delete from TXT where I_TXT=?");
        stmt.setLong(1, text.getId().longValue());
        stmt.execute();
   }
   finally
   {
        stmt.close();
   }
         }
      
         try
         {
   // insertion du text dans la table TXT
   stmt = conn.prepareStatement("insert into TXT (I_TXT, TXT_ORDER, TXT_VALUE) values (?, ?, ?)");
   if (text.getString().length() <= TEXT_MAX_LENGHT)
   {
        stmt.setLong(1, text.getId().longValue());
        stmt.setInt(2, 1);
        stmt.setString(3, text.getString());
        stmt.executeUpdate();            }
   else
   {
         String[] array = StringTools.split(text.getString(), TEXT_MAX_LENGHT);
         
                      for (int i = 0; i < array.length; i++)
         {
              stmt.setLong(1, text.getId().longValue());
              stmt.setInt(2, i);
              stmt.setString(3, array[i]);
              stmt.executeUpdate();
          }
   }
   
   // affecter le statement avec l'id du text référencé
   pSt.setLong(pIndex, text.getId().longValue());
      
         }
         finally
         {
   stmt.close();
         }
    }
   
    ...
}


Puis le fichier de mapping suivant :
Code:
<hibernate-mapping package="com.myexample">
     <class name="TextHolder" table="TEXT_HOLDER" lazy="true">
          <id name="id" column="ID">
   <generator class="increment"/>
          </id>

         <property name="name" column="NAME" />

         <property name="someText" column="I_TXT" >
   <type name="com.myexample.TextUserType">
       <param name="textIdColName">I_TXT</param>
   </type>
         </property>
         
     </class>   
</hibernate-mapping>



Actuellement je rencontre le problème suivant : lorsque dans la méthode nullSafeSet j'affecte un id à mon instance de Text, cela n'est pas reporté à l'instance que je manipule dans ma classe de test :

Code:
session = SessionFactoryHolder.currentSession();
tx = session.beginTransaction();
TextHolder holder = new TextHolder();
holder.setSomeText(new SnpsText("Some text for my example"));
holder.setName("my holder name");      
session.save(holder);
tx.commit();


Lorsque j'exécute ce code, holder.getSomeText().getTextId() retourne null... et deux lignes ont été insérée dans ma table TXT au lieu d'une seule.

Merci pour vos lumières


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