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 :

[Hibernate3] Gérer une liaison 1-n [Mapping]


Sujet :

Hibernate Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Mai 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 71
    Par défaut [Hibernate3] Gérer une liaison 1-n
    Bonjour à tous,

    étant quelque peu novice, je m'emmêle un peu les pinceaux avec Hibernate.

    Je cherche à générer une liaison 1-n sous la forme suivante :
    1 pays possède plusieurs villes, Une ville est liée à un seul pays.
    Au niveau base de données, cela est modélisé par :
    T_PAYS
    ID
    NAME
    USER_ID (*)
    (etc)

    (*) : dans mon exemple, un pays peut être lié à un utilisateur de ma base. Un genre de "pays préféré" pour l'utilisateur, en quelque sorte ...

    T_VILLE
    ID
    ID_PAYS
    NAME
    (etc)

    Au niveau de l'application, j'ai 2 choix :
    a) soit d'avoir un "ville.getPays()" : cela j'y arrive; soit d'avoir un "pays.getVilles()" et ça je n'y arrive pas. Par praticité, je préfère avoir la seconde solution, car l'idée est que mon DAO charge mon objet "Pays", avec les "Villes" déjà pré-chargées.
    Pour le moment (et un bon moment j'espère), il n'y a pas de problème de mise à jour dans la base : les données sont uniquement en lecture.

    J'utilise la version 3.4 d'Hibernate (JAR utilisé "hibernate-entitymanager-3.4.0.GA.jar"), ainsi que Spring. Ma base de données est Oracle.

    Voici le code de la classe "Pays" :
    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
    @Entity
    @Table(name = "T_PAYS")
    public class Pays implements Serializable {
    	private static final long serialVersionUID = 1L;
     
    	@Id
    	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pays_seq")
    	@SequenceGenerator(name = "pays_seq", allocationSize = 10, sequenceName = "SEQ_PAYS_ID")
    	private long id;
     
    	private String name;
     
    	@ManyToOne(fetch = FetchType.LAZY)
    	@JoinColumn(name = "USER_ID", nullable = true)
    	private User user;
     
    	@Column(name = "PAYS_COMMENT", nullable = true)
    	private String comment;
     
            // TODO que dois je specifier ici ??? 
            // Je m'emmêle les pinceaux ! :-/ 
    	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    	@JoinColumn(name = "PAYS_ID", nullable = true)
    	private Set<Ville> villes;
     
    	public long getId() {
    		return id;
    	}
     
            // etc : Getters / Setters en public
    }
    Voici le code de la classe Ville:
    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
    @Entity
    @Table(name = "T_VILLE")
    public class Ville {
     
    	@Id
    	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ville_seq")
    	@SequenceGenerator(name = "ville_seq", allocationSize = 10, sequenceName = "SEQ_VILLE_ID")
    	private long id;
     
            // note : facultatif, si j'arrivais à charger les villes directement dans un pays ... 
    	@Column(name = "PAYS_ID", nullable = false, insertable = false, updatable = false)
    	private Pays pays;
     
            // etc : getters / setters
    }
    Enfin, la classe de mon DAO :
    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
    @Repository
    public class PaysDAO extends MutableDAOImpl<Pays> {
     
    	public static Logger LOGGER = Logger.getLogger(PaysDAO.class);
     
    	/**
             * Private constructor used to prevent from instantiation.
             * 
             * Use DAOFactory.
             */
    	private PaysDAO () {
    		super();
    	}
     
    	public Class<Pays> getModelClass() {
    		return Pays.class;
    	}
     
    	@SuppressWarnings("unchecked")
    	public Pays findById(int id) throws DAOException {
    		try {
    			String qlString = "select c from Pays c where c.id=:id";
    			Query query = em.createQuery(qlString);
    			query.setParameter("id", id);
    			return query.getSingleResult();
    		} catch (Exception e) {
    			LOGGER.error(e.getMessage(), e);
    			throw new DAOException(e);
    		}
    	}
     
    	@SuppressWarnings("unchecked")
    	public List<Pays> findByName(String name) throws DAOException {
    		try {
    			String qlString = "select c from Pays c where c.name=:name";
    			Query query = em.createQuery(qlString);
    			query.setParameter("name", name);
    			return query.getResultList();
    		} catch (Exception e) {
    			LOGGER.error(e.getMessage(), e);
    			throw new DAOException(e);
    		}
    	}
     
    	@SuppressWarnings("unchecked")
    	public List<Pays> findByUser(long userId) throws DAOException {
    		try {
    			String qlString = "select c from Pays c where c.user.id=:userId";
    			Query query = em.createQuery(qlString);
    			query.setParameter("userId", userId);
    			return query.getResultList();
    		} catch (Exception e) {
    			LOGGER.error(e.getMessage(), e);
    			throw new DAOException(e);
    		}
    	}
    }
    Bref, comment gérer une liaison 1-n directement dans la classe "Pays", à coup d'annotations ? Que je puisse charger dans mon DAO directement le Pays et ses Villes ?

    Merci d'avance pour vos éclaircissements si vous en avez.

    Très cordialement,

  2. #2
    Membre émérite Avatar de Gardyen
    Homme Profil pro
    Bio informaticien
    Inscrit en
    Août 2005
    Messages
    637
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bio informaticien

    Informations forums :
    Inscription : Août 2005
    Messages : 637
    Par défaut
    suivant la doc hibernate, ton mapping est fait à l'envers

    Voilà leur exemple:
    @Entity
    public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
    }

    @Entity
    public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
    }
    adapté à ton cas ça donnerait... ça ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @Entity
    public class Pays {
        @OneToMany(mappedBy="pays")
        public Set<Ville> getVilles() {
        ...
    }
     
    @Entity
    public class Ville {
        @ManyToOne
        @JoinColumn(name="PAYS_ID")
        public Pays getPays() {
        ...
    }

  3. #3
    Membre confirmé
    Inscrit en
    Mai 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 71
    Par défaut
    Désolé de ma réponse tardive, j'étais passé entre temps sur autre chose ...

    J'hésite, du côté de la classe Ville, à mettre ceci :
    soit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    @Column(name = "PAYS_ID", nullable = false, insertable = false, updatable = false)
    private Pays pays;
    ou :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    @ManyToOne
    @JoinColumn(name="trade_config_id")
    private NxTradeConfig tradeConfig;
    Avec les 2 possibilités, j'ai l'erreur suivante, quand j'essaye de lancer un test :
    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
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.truc.Pays.villes, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
    	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
    	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
    	at org.hibernate.collection.PersistentSet.toString(PersistentSet.java:332)
    	at java.lang.String.valueOf(String.java:2826)
    	at java.lang.StringBuilder.append(StringBuilder.java:115)
    	at com.truc.PaysDaoTest.testFirst(NxTradeConfigDaoTest.java:34)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Dans mon test, j'ai le code suivant :
    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
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "/test-data-context.xml" })
    @TransactionConfiguration(transactionManager = "nxTxManager", defaultRollback = false)
    public class PaysDaoTest {
    	@Autowired
    	private PaysDAO dao;
     
    	@Test
    	public void testList() throws Exception {
    		List<Pays> l = dao.findAll();
    		Assert.assertNotNull(l);
    		Assert.assertTrue(l.size() != 0);
    	}
     
    	@Test
    	public void testFirst() throws Exception {
    		Pays l = dao.getById(Long.valueOf("1"));
    		Assert.assertNotNull(l);
    		Assert.assertTrue(l.getVilles() != null);
    		System.out.println("villes=" + l.getVilles());
    		Assert.assertTrue(l.getVilles().size() == 4);
    	}
    }
    L'erreur survient, pas lorsque l'objet "Pays" est chargé, mais lorsque l'on tente d'accéder à la collection des villes ("pays.getVilles()").

  4. #4
    Membre émérite Avatar de Gardyen
    Homme Profil pro
    Bio informaticien
    Inscrit en
    Août 2005
    Messages
    637
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bio informaticien

    Informations forums :
    Inscription : Août 2005
    Messages : 637
    Par défaut
    cette erreur vient du lazy-loading, tu essaies d’accéder à des propriétés pas encore chargées alors que ta session est fermée.

  5. #5
    Membre confirmé
    Inscrit en
    Mai 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 71
    Par défaut
    Je rajoute la balise suivante en en-tête de ma classe "PaysDaoTest":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Throwable.class)
    (Je me suis inspiré d'autre classes de test de DAO et de savoir si, pour d'autres objets avec des relations "1-n" ou "n-n", si j'avais accès aux collections : en premier abord, j'ai eu la même erreur "LazyInitializationException"), puis j'ai cherché dans le code s'il n'y avait pas des annotations en plus ...

    Mais maintenant, je n'ai plus de "LazyInitializationException", mais l'erreur suivante (toujours quand j'essaye d'accéder à la liste :
    (pourtant, j'ai vérifié : les deux classes implémentent l'interface "Serializable", et les 2 classes ont un "serialVersionUID" précisé).
    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
    org.hibernate.type.SerializationException: could not deserialize
    	at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:188)
    	at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:211)
    	at org.hibernate.type.SerializableType.fromBytes(SerializableType.java:105)
    	at org.hibernate.type.SerializableType.get(SerializableType.java:62)
    	at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:184)
    	at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:173)
    	at org.hibernate.type.AbstractType.hydrate(AbstractType.java:105)
    	at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2124)
    	at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1404)
    	at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1332)
    	at org.hibernate.loader.Loader.getRow(Loader.java:1230)
    	at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:603)
    	at org.hibernate.loader.Loader.doQuery(Loader.java:724)
    	at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
    	at org.hibernate.loader.Loader.loadCollection(Loader.java:2015)
    	at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:59)
    	at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:587)
    	at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:83)
    	at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1743)
    	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:366)
    	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
    	at org.hibernate.collection.PersistentSet.toString(PersistentSet.java:332)
    	at java.lang.String.valueOf(String.java:2826)
    	at java.lang.StringBuilder.append(StringBuilder.java:115)
    	at com.truc.PaysDaoTest.testFirst(NxTradeConfigDaoTest.java:37)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
    	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Caused by: java.io.StreamCorruptedException: invalid stream header: C3104F2A
    	at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:783)
    	at java.io.ObjectInputStream.<init>(ObjectInputStream.java:280)
    	at org.hibernate.util.SerializationHelper$CustomObjectInputStream.<init>(SerializationHelper.java:223)
    	at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:180)
    	... 52 more

  6. #6
    Membre émérite Avatar de Gardyen
    Homme Profil pro
    Bio informaticien
    Inscrit en
    Août 2005
    Messages
    637
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bio informaticien

    Informations forums :
    Inscription : Août 2005
    Messages : 637
    Par défaut
    en cherchant un peu, je suis tombé sur ce thread
    Apparemment l'erreur peut apparaître en cas de mapping erroné pour un many-to-one

    comment as-tu modifié tes 2 classes ?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Opérer une liaison entre 2 DBLookup
    Par pey dans le forum Bases de données
    Réponses: 3
    Dernier message: 10/12/2004, 10h11
  2. [dbase] Possibilité de gèrer une base via c++?
    Par WriteLN dans le forum C++
    Réponses: 6
    Dernier message: 08/11/2004, 17h27
  3. Gérer une barre d'outils
    Par Jean Claude BOULET dans le forum Access
    Réponses: 2
    Dernier message: 07/10/2004, 22h54
  4. [ODBC][WINDOWS] gérer une base via ODBC
    Par narmataru dans le forum Windows
    Réponses: 2
    Dernier message: 19/12/2003, 13h36
  5. partage d'une liaison ADSL
    Par hassen dans le forum Développement
    Réponses: 6
    Dernier message: 20/10/2003, 20h10

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