Quick links: Content - sections - sub sections
EN FR
Quick Search Advanced search
 
Page

  [Opened] Ajout à jDao

Posted by Tpt on 03/16/2011 14:47

Bonjour, je viens de remarquer que jDao ne possède pas une fonctionnalité qui serai bien pratique tout en nécessitant peu de modification : pouvoir faire des jointures où la table où le champ d'une table qui est la clé étrangère de la table jointe ne se trouve pas dans la table principale. On aurait alors une requête du type :

FROM products AS p LEFT JOIN manufacturers AS man ON (p.id_manufacturer = man.id),  categories AS cat WHERE cat.id_cat = man.id_cat

Il suffirait d'ajouter une propriété comme "onforeigntable" aux balises <foreigntable> et <optionalforeigntable>.

Serait-t-il possible d'intégrer cette fonctionnalité à jDao pour la version 1.3 de Jelix ?

Merci d'avance !

  [Opened] Ajout à jDao

Reply #1 Posted by laurentj on 03/17/2011 13:23

Bonjour,

ce que tu veux, c'est un support de table de jointure. Ce n'est pas possible dans l'esprit "dao". Car la liste résultante peux retourner plusieurs fois le même enregistrement principal (avec des valeurs différentes pour les tables annexes). une relation n-n.

Il suffirait d'ajouter une propriété comme "onforeigntable" aux balises <foreigntable> et <optionalforeigntable>.

je doute qu'"il suffise".

Serait-t-il possible d'intégrer cette fonctionnalité à jDao pour la version 1.3 de Jelix ?

Ce n'est pas ma priorité. Maintenant, si il y a un volontaire pour un patch, qui ne fonctionnerai que pour les tables intermédiaire qui ne soient pas des vrais tables de jointures, pourquoi pas.

  [Opened] Ajout à jDao

Reply #2 Posted by Tpt on 06/05/2011 17:23

Je me permet de relancer le topic avec un patch qui permet de spécifier la table dans laquelle se trouve la où les clé(s) étrangère(s) via la propriété "onforeigntable" qui contient le nom de la table dans la dao. Le générateur de la clause from à été réécrit en grande partie pour que les jointures se fassent correctement : les tables sont triés dans un tableau suivant la table contenant leur clé étrangère ce qui permet de les joindre juste après cette table. Le tout est visiblement totalement rétrocompatible avec l'existant : les dao fournies avec jelix fonctionnent bien.

Voici le patch : http://genewiki.legtux.org/jelix-trunk-p(..)

Pardon pour la piètre qualité du code, je ne suis qu'un jeune amateur.

Voici un exemple :

Les tables :

		<primarytable name="history" primarykey="id" />
<code>
		<foreigntable name="pages" primarykey="id" onforeignkey="page_id" />
		<foreigntable name="data" realname="people_data" primarykey="id" onforeignkey="id" />
		<optionalforeigntable name="birth" realname="people_events" primarykey="id" onforeignkey="birth_id" onforeigntable="data" />
		<optionalforeigntable name="death" realname="people_events" primarykey="id" onforeignkey="death_id" onforeigntable="data" />
		<optionalforeigntable name="birth_place" realname="places" primarykey="id" onforeignkey="place_id" onforeigntable="birth" />
		<optionalforeigntable name="death_place" realname="places" primarykey="id" onforeignkey="place_id" onforeigntable="death" />
		<optionalforeigntable name="name_id" realname="pages" primarykey="id" onforeignkey="name_id" onforeigntable="data" />
		<optionalforeigntable name="name" realname="history" primarykey="id" onforeignkey="version_id" onforeigntable="name_id" />
		<optionalforeigntable name="name_data" realname="names_data" primarykey="id" onforeignkey="id" onforeigntable="name" />
</code>

La clause from :

$this->_fromClause = ' FROM `'.$this->_conn->prefixTable('history').'` AS `history`, `'.$this->_conn->prefixTable('pages').'` AS `pages`, `'.$this->_conn->prefixTable('people_data').'` AS `data` LEFT JOIN `'.$this->_conn->prefixTable('people_events').'` AS `birth` ON ( `data`.`birth_id`=`birth`.`id`) LEFT JOIN `'.$this->_conn->prefixTable('places').'` AS `birth_place` ON ( `birth`.`place_id`=`birth_place`.`id`) LEFT JOIN `'.$this->_conn->prefixTable('people_events').'` AS `death` ON ( `data`.`death_id`=`death`.`id`) LEFT JOIN `'.$this->_conn->prefixTable('places').'` AS `death_place` ON ( `death`.`place_id`=`death_place`.`id`) LEFT JOIN `'.$this->_conn->prefixTable('pages').'` AS `name_id` ON ( `data`.`name_id`=`name_id`.`id`) LEFT JOIN `'.$this->_conn->prefixTable('history').'` AS `name` ON ( `name_id`.`version_id`=`name`.`id`) LEFT JOIN `'.$this->_conn->prefixTable('names_data').'` AS `name_data` ON ( `name`.`id`=`name_data`.`id`)';

  [Opened] Ajout à jDao

Reply #3 Posted by laurentj on 06/05/2011 19:16

@tpt :

Premièrement, ton patch ne nous ait pas accessible. il faut un login/mot de passe.

Deuxièmement, mes explications n'ont pas été assez claires apparemment. Ce n'est pas logique, dans l'esprit DAO, de faire de telle jointure, parce que tu vas te retrouver avec des enregistrements de la table primaire, en multiple exemplaires dans la liste de résultat. Et ce n'est absolument pas ce qu'on attend d'un mapping relationnel objet. Quand on fait du mapping relationnel objet, que ce soit avec DAO, active record ou autre, on doit avoir un objet = un record. et pas 15000 objets représentant le même record.

Les données que l'on veut récupérer lors d'une relation n-n, doivent être logiquement récupérée via une méthode de l'objet correspondant au record de la table primaire. Et pour cela, pour les relations n-n, ce serait plus logique de pouvoir définir dans le xml, via une balise property ou une nouvelle balise <has_several> par exemple, que cette propriété contient la liste des enregistrements d'un autre dao, en y indiquant la table de jointure.

Un truc dans le genre :

<code>
 <record>
   <has_several  name="birth_events" dao="monmodule~people_events"
              jointable="people_data" leftkey="id" rightkey="birth_id" />
 </record>
</code>

Cela génère une methode birth_events() sur la classe record de history. celle ci execute une requete faisant la jointure entre le people_data et people_events. Et en PHP, on n'aurait plus qu'à faire :

<code>
  $historyList = jDao::create('history')->findAll();

  $historyRecord = $historyList->fetch(); // récupération d'un enregistrement

  // on récupère la liste des enregistrements dans people_events 
  // correspondant à notre record
  $birthEventsList = $historyRecord->birth_events(); 
  // $birthEventsList est un recordset comme d'hab
</code>

  [Opened] Ajout à jDao

Reply #4 Posted by Tpt on 06/05/2011 20:46

Pardon pour la protection du fichier je viens de l'enlever, il est maintenant accessible. Le problème, si je comprend bien, c'est la multiplication des fichier de DAO pour représenter les mêmes données, dans mon exemple ce serait créer une DAO pour les personnes, une pour les naissance et une pour les personnes+naissance qui doublonnerai.

Merci pour ta patience !

PS : Si je puis abuser de ta bonté, que penses-tu de mon patch au point de vu de sa qualité de code ? Cela m’aiderai à m'améliorer.

PS 2 totalement hors sujet : J'ai créé une réponse pour les suggestions Open Search ainsi qu'une pour le fichier de description Open Search. Elles seraient-il intégrable à Jelix où leur usage est trop limité ?

  [Opened] Ajout à jDao

Reply #5 Posted by laurentj on 06/05/2011 22:32

que penses-tu de mon patch au point de vu de sa qualité de code ?

je l'ai regardé très rapidement, mais ça n'a pas l'air trop mal. Maintenant je ne me suis pas replongé dans le code du générateur pour te dire si oui ou non le code est correcte à 100% :-)

pour la réponse open search, je ne sais pas. faudra que j'étudie ça. Mais d'ici quelques semaines on va ouvrir un site pour cataloguer ce genre de contributions qui ne sont pas incluse de base dans jelix (il y aura des modules, plugins etc..).

  [Opened] Ajout à jDao

Reply #6 Posted by Tpt on 06/06/2011 10:33

Merci pour ton attention !

  [Opened] Ajout à jDao

Reply #7 Posted by lebourja on 03/31/2012 07:24

Bonjour,

je relance ce thread pour savoir s'il y a du nouveau car il semblerai que j'ai le même besoin.

J'ai une datasource basée sur deux tables avec une jointure 1<->1 :

<datasources>
		<primarytable name="town_lang" realname="town_lang"
			primarykey="id,language" />
		<foreigntable name="town" realname="town" primarykey="id"
			onforeignkey="id" />
</datasources>

Et je souhaiterais ajouté une optionalforeigntable avec également une relation 1<->1

<optionalforeigntable name="state" realname="state" primarykey="id" onforeignkey="state"/>

seulement voilà, ma clef étrangère state n'est pas dans town_lang mais dans town (town_lang contient les champs internationalisés).

j'ai essayé plusieurs astuces, style mettre le nom de la table avec la foreignkey, définir un alias 'stateid'... mais je ne m'en sors pas.

Avez-vous une solution ou n'est ce pas une évolution intéressante d'ajouter onforeigntable comme le proposait Tpt (tout en restant dans du relationnel 1<->1 bien sur :) )?

Jacques

  [Opened] Ajout à jDao

Reply #8 Posted by laurentj on 03/31/2012 15:01

@jacques, à mon avis, tu as pris le problème à l'envers. Ta table principale, c'est pas town_lang, mais town... ;-)

  [Opened] Re: Ajout à jDao

Reply #9 Posted by lebourja on 03/31/2012 18:41

Bah, je ne vois pas comment faire pour avoir un mondao.get(id,lang) qui me retourne un objet complet si je mets la jointure dans l'autre sens. Et c'est vrai que je cherchais à faire un dao qui me permette de faire cela. Mais tu as probablement raison, je dois pouvoir m'en sortir en faisant la jointure dans l'autre sens et en ajoutant au dao une méthode getLocalized(id,lang). Comme quoi un regard extérieur ... D'ailleurs je teste... Yes thanks ça marche :-)

ceci dit, l'évolution pourrait quand même être intéressante ;-)

merci + jacques

 
Page
  1. Re: Ajout à jDao