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

Persistance des données Java Discussion :

[ORM]Problème de conception


Sujet :

Persistance des données Java

  1. #1
    Membre éclairé Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    Juillet 2004
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2004
    Messages : 584
    Par défaut [ORM]Problème de conception
    Bonjour,

    Au lancement de mon appli, je fais une requête pour renseigner mes objets. J'utilise JPA/EclipseLink.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	public List<Continent> findAllContinent() {
    		Query query = entityManager.createQuery("select c from "
    				+ Continent.class.getSimpleName() + " c order by c.continentName");
    		return query.getResultList();
    	}

    Par la suite, je fais une requête pour rechercher les continents qui commencent ou contiennent une chaine de caractère (ex: ri).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    	public List<StationGrouping> findStationGroupingByName(String name) {
    		Query query = entityManager.createQuery("select sg from "
    				+ StationGrouping.class.getSimpleName() + " sg where LOWER(sg.stationGroupingName) like :name order by sg.stationGroupingName");
    		query.setParameter("name", "%" + name.toLowerCase()  +"%");
    		return query.getResultList();
    	}
    En faisant cela, je me retrouve avec plusieurs instance du même continent
    1ére requête:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Asie             org.worlddatabinding.domain.Continent@1127a1d8
    Amerique      org.worlddatabinding.domain.Continent@49c06a6d
    Afrique         org.worlddatabinding.domain.Continent@57125f92
    2ème requête (recherche des continents avec "ri" dans le nom)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Amérique      org.worlddatabinding.domain.Continent@40f274b4
    Afrique         org.worlddatabinding.domain.Continent@6dcbf6bb
    J'ai donc un problème de conception important

    Comment éviter d'avoir des instances du même objet ?
    Comment faire une recherche avec critères et synchroniser les données de la Bdd et celles du Domain ?

    D'avance merci pour votre aide

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 16
    Par défaut
    Bonjour,

    Pourquoi "Asie" est retourné dans la première requête?


    Par contre je ne comprends pas votre problème de conception?
    Les deux requêtes n'utilisent pas le même entityManager et donc les instances retournées comme résultat sont différentes. Par contre les deux requêtes doivent retourner des objets avec les même ids base de données. Non?

  3. #3
    Membre éclairé Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    Juillet 2004
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2004
    Messages : 584
    Par défaut
    Bonjoir

    Citation Envoyé par vhalalla Voir le message
    Pourquoi "Asie" est retourné dans la première requête?
    Asie est retourné car je fais un find de tous mes continents dans la base.
    ( findAllContinent() )

    Par contre je ne comprends pas votre problème de conception?
    Les deux requêtes n'utilisent pas le même entityManager et donc les instances retournées comme résultat sont différentes. Par contre les deux requêtes doivent retourner des objets avec les même ids base de données. Non?
    Oui les objets retournés ont le même ID mais j'ai deux instance différentes.
    Ce qui me pose problème par la suite.
    Sans rentrer dans le détails, j'ai un Tree représentant mes données.
    Pour le remplir je fais un findAllContinent().
    Je sélectionne un continent (ex:Asie) pour y ajouter un pays (enfant)
    Un wizard de création de Pays s'ouvre.
    Je me rend compte que le continent (parent) sélectionné à l'origine ne me convient pas. Je souhaite le modifier (ex:Amerique)et je fais donc une requête findContinentByName() pour avoir une liste limiter de continent à jour.

    J'ai donc 2 instances d'Amerique :
    • 1 dans le Tree -> récupérer via la 1ére requete
    • 1 utilisé dans le wizard de création de Pays -> 2ème requete


    Merci pour votre aide

  4. #4
    Membre chevronné
    Homme Profil pro
    Développeur Java
    Inscrit en
    Avril 2004
    Messages
    265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Avril 2004
    Messages : 265
    Par défaut
    Salut,
    J'aurais tendance à dire que si problème de conception il y a, il ne réside pas dans le fait d'avoir des instances différentes (c'est même obligatoire, si les instances étaient partagées tout le monde verrait les modifications faites sur les entités sans qu'elles aient été mergées). => Le problème réside plutôt dans le fait d'avoir besoin de la même instance.
    Si il y a besoin de comparer ces entités, il suffit de surcharger la méthode equals (ne pas comparer les références), peut-être hashCode (selon la méthode de comparaison), afin que les entités soient "égales" même si ce sont des instances différentes.

  5. #5
    Membre éclairé Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    Juillet 2004
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2004
    Messages : 584
    Par défaut
    Salut,

    Merci pour la réponse. Mon problème vient du fait que je fais du dataBinding avec JFace entre mon Tree et mes objets du domain.
    Mon tree comporte un instance des mes objets et lorsque je fais une seconde requête, je ne travail plus sur la même instance.... Donc mon Tree ne se met pas à jour. Le binding est brisé.

    Sinon, je pensais faire à chaque requête "find", une mise à jour de mes objets du domain. Mais je ne sais pas si c'est plus propre que de comparer mes objets

  6. #6
    Membre éclairé Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    Juillet 2004
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2004
    Messages : 584
    Par défaut
    Bonjour,

    Je tourne en rond sur ce sujet et je n'arrive pas à m'en sortir.

    Le fait de comparer mes entités du domain (détachées du contexte de persistance) et ceux de ma nouvelle requête de recherche ne m'avance guère
    Car je compare mes 2 instances et utilise mon entité (détachée) car c'est elle qui est liée avec mon Tree (dataBinding).

    Autant utiliser directement, les objets du domain sans faire de requête
    Mais cela ne me plait pas car, si un autre utilisateur ajoute un continent dans la bdd, je ne pourrai l'utiliser. Je perd aussi l'opportunité de faire des recherches "faciles" et "efficaces" type:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Query query = entityManager.createQuery("select c from "
    				+ Continent.class.getSimpleName() + " c where LOWER(c.continentName) like :name ");
    		query.setParameter("name", "%" + name.toLowerCase()  +"%");
    D'avance merci

  7. #7
    Membre Expert
    Avatar de Patriarch24
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2003
    Messages
    1 047
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 047
    Par défaut
    Salut,
    J'aurais tendance à dire que si problème de conception il y a, il ne réside pas dans le fait d'avoir des instances différentes (c'est même obligatoire, si les instances étaient partagées tout le monde verrait les modifications faites sur les entités sans qu'elles aient été mergées). => Le problème réside plutôt dans le fait d'avoir besoin de la même instance.
    Si il y a besoin de comparer ces entités, il suffit de surcharger la méthode equals (ne pas comparer les références), peut-être hashCode (selon la méthode de comparaison), afin que les entités soient "égales" même si ce sont des instances différentes.
    +1.
    C'est une bonne pratique de définir equals et hashcode pour les entités. Ainsi, en les stockant par exemple dans un Set, on n'a pas de doublon.

  8. #8
    Membre éclairé Avatar de pingoui
    Homme Profil pro
    Activité professionnelle sans liens avec le developpement
    Inscrit en
    Juillet 2004
    Messages
    584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Activité professionnelle sans liens avec le developpement
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2004
    Messages : 584
    Par défaut
    Merci pour votre aide.
    J'ai bien redéfini les méthodes hashCode et equals et utiliser un HashSet au lieu d'un ArrayList.
    Mais j'ai toujours mon bug
    world
    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
     
    public class World extends AbstractModelObject{
     
    	private static World world;
    	private Set<Continent> continents = new HashSet<Continent>();
     
    	public static World getInstance() {
    		if (world == null) {
    			world = new World();
    		}
    		return world;
    	}
     
    //GETTER AND SETTER
    	@Override
    	public int hashCode() {
    		final int prime = 31;
    		int result = 1;
    		result = prime * result
    				+ ((continents == null) ? 0 : continents.hashCode());
    		return result;
    	}
     
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (!(obj instanceof World))
    			return false;
    		World other = (World) obj;
    		if (continents == null) {
    			if (other.continents != null)
    				return false;
    		} else if (!continents.equals(other.continents))
    			return false;
    		return true;
    	}
     
    }
    Continent
    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
     
    @Entity
    @Table(name = "T_CONTINENT")
    public class Continent extends AbstractModelObject implements Serializable {
     
    	private static final long serialVersionUID = 1L;
     
    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	@Column(name = "continent_id")
    	private long continentId;// Identifiant du continent
     
    	@Version
    	private int version;
     
    	@Column(name = "continent_name")
    	private String continentName;// Nom du continent
     
    	@OneToMany(mappedBy = "continent", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH  })
    	private Set<Country> countries = new HashSet<Country>();
     
     
    	public Continent() {}
     
    	public Contienent(String continentName) {
    		super();
    		this.continentName = continentName;
    	}
     
    //GETTER AND SETTER
     
    	public void addCountry(Country country) {
    		countries.add(country);
    		country.setContinent(this);
            firePropertyChange("countries", null, this.countries);
    	}
     
    	public void deleteCountry(Country country) {
    	}
     
    	@Override
    	public int hashCode() {
            int result;
            result = getContinentName().hashCode();
            result = (int) (31 * result + getContinentId());
            return result;
    	}
     
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (!(obj instanceof Continent))
    			return false;
    		Continent other = (Continent) obj;
    		if (getContinentId() != other.getContinentId())
    			return false;
    		if (getContinentName() == null) {
    			if (other.getContinentName() != null)
    				return false;
    		} else if (!getContinentName().equals(other.getContinentName()))
    			return false;
    		return true;
    	}
     
    }
    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
    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
     
    @Entity
    @Table(name = "T_COUNTRY")
    public class Country extends AbstractModelObject{
     
    	private static final long serialVersionUID = 1L;
     
    	@Id
    	@GeneratedValue(strategy = GenerationType.IDENTITY)
    	@Column(name = "country_id")
    	private long countryId;// Identifiant du pays
     
    	@Version
    	private int version;
     
    	@Column(name = "country_name")
    	private String countryName;// Nom du pays
     
    	@ManyToOne(fetch=FetchType.LAZY)
    	@JoinColumn(name = "groupingOfStation_id", nullable = false)
    	private Continent continentParent;// Le parent du pays -> le continent
     
    	@OneToMany(mappedBy = "country", cascade = {  CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
    	private Set<Area> areas = new HashSet<Area>(); // La liste des régions
     
     
    	public Country() {
    		super();
    	}
     
    	public Country(String countryName) {
    		super();
    		this.countryName = countryName;
    	}
     
    //GETTER AND SETTER
    		@Override
    	public int hashCode() {
            int result;
            result = getCountryName().hashCode();
            result = (int) (31 * result + getCountryId());
            return result;
    	}
     
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (!(obj instanceof Country))
    			return false;
    		Country other = (Country) obj;
    		if (getCountryId() != other.getCountryId())
    			return false;
    		if (getCountryName() == null) {
    			if (other.getCountryName() != null)
    				return false;
    		} else if (!getCountryName().equals(other.getCountrytName()))
    			return false;
    		return true;
    	}
    }

    Je vois où se trouve mon bug mais je ne sais comment le résoudre efficacement sans faire une bidouille.

    A l'ouverture de l'appli, je crée un singleton world qui contient mes continents
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    		World world = world.getInstance();
    		Set set = new HashSet(getServices().getContinentService().findAllContinent());
    		world.setContinents(set);
    Couche service
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	public List<Continent> findAllContinent() {
    		return continentDao.findAllContinent();
    	}
    Couche DAO
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	public List<Continent> findAllContinent(){
    		Query query = entityManager.createQuery("select c from "
    				+ Continent.class.getSimpleName()");
    		return query.getResultList();
    	}
    Mon Tree représentant le monde contient désormais un HashSet de continents.

    Ensuite, je selectionne un continent de mon Tree.
    J'ouvre un wizard de création de pays. Je veux changer de continent parent
    Un autre wizard s'ouvre, et me permet de faire une recherche de continent avec une chaine de caractères.
    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
     
    		public void handleEvent(Event event) {
    			//Si l'évenement est un clic sur le bouton de recherche
    			if (event.widget == searchButton) {			
    				dico = new HashMap<String, Continent>();
    				for (Continent conti : uiController.getServices().getContinentService().findContinentsByName(searchText.getText())){
    					//on ajoute le resultat de la requete dans un dico
    					dico.put(g.getContinentName(), g);
    					//On ajoute le resultat dans la List
    					resultList.add(g.getContinentName());
    				}
    			}
    			//Si l'événement est une selection dans la liste
    			if (event.widget == resultList) {
    				for(String result : resultList.getSelection()){	
    					//On récupére le résultat dans le dico
    					continentParent = (Continent)dico.get(result);
    				}
    				setPageComplete(isPageComplete());
    				getWizard().getContainer().updateButtons();
    			}	
    		}
     
    ////////
    	public boolean performFinish() {
    		AddStationWizard wizardParent = (AddStationWizard)parentPage.getWizard();
    		wizardParent.setGroupingOfStationParent(continentParent);
    		parentPage.refreshParentText(continent.getContinentName());
    		return true;
    	}
    Cette recherche se fait via ma couche service
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    	public List<Continent> findContinentsByName(String name) {
    		return continentDao.findContinentsByName(name);
    	}
    et ma couche DAO
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    	public List<Continent> findContinentsByName(String name) {
    		Query query = entityManager.createQuery("select c from "
    				+ Continent.class.getSimpleName() + " c where LOWER(c.continentName) like :name");
    		query.setParameter("name", "%" + name.toLowerCase()  +"%");
    		return query.getResultList();
    	}
    Après validation de mon wizard, j'obtiens un continent résultant de ma requête findContinentsByName

    Même si désormais j'ai redéfini la méthode haschCode et equals de mes entities, j'ai toujours un problème de conception...
    D'un côté, j'ai un HashSet avec des continents et de l'autre une List de continent
    J'ai essayé de prendre l'iD du continent issu de ma requête findContinentsByName et de récupérer l'entity correspondant à cet ID dans mon HashSet.... mais je ne trouve pas cette solution très propre.

Discussions similaires

  1. Méthode Finalize et problème de conception
    Par phryos dans le forum Langage
    Réponses: 4
    Dernier message: 19/04/2006, 11h04
  2. [VB6][UserControl et OCX]Problème de conception
    Par jacma dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 19/01/2006, 22h37
  3. Petit problème de conception sur access
    Par coooookinette dans le forum Modélisation
    Réponses: 3
    Dernier message: 18/12/2005, 18h24
  4. Gestion des départements problème de conception
    Par snoopy69 dans le forum Modélisation
    Réponses: 7
    Dernier message: 11/10/2005, 13h08
  5. Problème de conceptions de tables
    Par dtavan dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 23/05/2004, 23h13

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