Problema relazioni tra tabelle mssql

Ciao ragazzi,

mi sto introducendo nel mondo yii e non riesco a trovare risposte ai miei perchè ne dalla guida ufficiale ne tra i vari forum nonostante la situazione sia abbastanza semplice.

Ho due tabelle e due modelli generati automaticamente da yii: TFATTVENDITA e DFATTVENDITA dei quali voglio fare un banale join su una FOREIGN KEY.

Vi posto le relazioni che ho stabilito io tra le tabelle:




class TFATTVENDITA extends CActiveRecord{

public function relations()

        {               

                return array(                    

                    'D_FATT_VENDITA' => array(self::HAS_MANY,'DFATTVENDITA','ID_FATTURA','joinType'=>'INNER JOIN')

                );

        }

}


class DFATTVENDITA extends CActiveRecord{

public function relations()

        {

            return array(

               'T_FATT_VENDITA' => array(self::BELONGS_TO,'TFATTVENDITA','ID_FATTURA','joinType'=>'INNER JOIN'),

             

            );

        }

}



Ora nel controller eseguo il join:


$join=TFATTVENDITA::model()->with('D_FATT_VENDITA')->findAll(array("alias"=>'TFATT','condition'=>"TFATT.ID_FATTURA='1305985'"));



Il mio problema ora è che se vado a leggere la variabile $join ho correttamente tutti i campi della tabella TFATTVENDITA ma quando provo a richiamare quelli di DFATTVENDITA ottengo un errore:

Property "TFATTVENDITA.COD_PRODOTTO" is not defined.

Sicuramente sbaglio qualcosa, ma data la banalità della situazione non capisco proprio cosa.

Qualcuno sa darmi una dritta?

Gianlu

Per il momento ti porgo una domanda:

Il model contiene lìattributo "COD_PRODOTTO"?

Certamente,

il model DFATTVENDITA contiene il campo COD_PRODOTTO, non ho postato il codice per evitare di farlo diventare decisamente lungo. Ad ogni modo è stato generato automaticamente con gii sulla base della tabella già esistente.

La mia sintassi è corretta almeno?

Gianluca

Va bene che il model DFATTVENDITA contenga il campo COD_PRODOTTO. Però l’errore dice che il model TFATTVENDITA non ha il campo COD_PRODOTTO. Quindi riformulo la domanda:

Il model TFATTVENDITA ha il campo COD_PRODOTTO.

Eh no, è il motivo per cui voglio fare il join. TFATTVENDITA ha come PK il campo ID_FATTURA che utilizzo per fare il join con DFATTVENDITA che contiene al suo interno il campo COD_PRODOTTO.


$join=TFATTVENDITA::model()->with('D_FATT_VENDITA')->findAll(array("alias"=>'TFATT','condition'=>"TFATT.ID_FATTURA='1305985'"));

In questo caso in base alle relazioni che ho costruito mi aspetto di avere nella variabile $join i record che soddisfano la mia condizione con tutti i campi relativi all’unione delle 2 tabelle.

Quello che voglio fare adesso è ciclare sulla variabile e stampare ad esempio qualcosa di questo tipo:


foreach ($join as $prova){

    echo $prova->COD_PRODOTTO."</br>";

   

    

}

Dov’è l’errore?

ActiveRecord di Yii non funziona in questo modo. Se fai una join, tu ti aspetti una cosa, ma ne accade un’altra. Se ho ben capito, tu ti aspetti che, facendo il join tra due tabelle, la variabile risultante contenga tutti i campi della join, ma non è così.

Nell’active record di Yii, quando definisci una relazione, e quando la usi in una join, per accedere al suo attributo devi passare dalla relazione.

PS. Ti chiedo la cortesia di usare codice standard in modo che sia condivisibile con tutti e di non usare nomi di tabelle e di campi uppercase.

Si esatto è quello che mi aspettavo.

Ma a questo punto come faccio a passare dalla relazione così come dici tu?

Perdona gli uppercase ma il mio db è fatto così: nomi di tabelle e campi in maiuscolo…

Provo a risponderti con un esempio.

Supponiamo di avere due model A e B. E supponiamo che A.b_id sia una chiave esterna che punta a B. A questo punto A avrà una relazione definita dentro al model. Dopo una join, per accedere all’attributo di b devi fare questo:

A->nome_relazione->attributo_di_b

Se sei soddisfatto della risposta, premi il più verde in basso a destra =).

Credo di aver compreso quello che dici e la logica di funzionamento.

Ho risolto andando a leggere la variabile join in questo modo ma ad essere sincero qualcosa non mi torna ancora.


foreach ($join as $prova){    

foreach ($prova->D_FATT_VENDITA as $temp){        

echo $temp->COD_PRODOTTO;    

}   

}

Così facendo secondo me non sto sfruttando le potenzialità dell’eager loading approach perchè con questo join:

$join=TFATTVENDITA::model()->findAll(array(‘condition’=>“t.ID_FATTURA=1305985”));

ottengo lo stesso risultato.

Prova con questo snippet:




foreach ($join as $prova){

    echo $prova->D_FATT_VENDITA->COD_PRODOTTO;

}



Avevo tentato ma mi dice:

Trying to get property of non-object

e mi evidenzia le riga dell’echo come errata.

Quindi $prova->D_FATT_VENDITA mi restituisce a sua volta un array di oggetti.

Quello che volevo capire è se esite una sintassi un po’ meno pesante di quella che ho usato per accedere ai campi di questo join…

Per incominciare, potresti provare a dare dei nomi più semantici alle variabili. La sintassi migliorerà di conseguenza.

Non capisco cosa è TFATTVENDITA. Vorrei suggerirti di non comprimere i nomi delle cose. Se, per esempio, T sta per tabella, potresti usare il nome TabellaFattureVendita. Se la D sta per dettaglio, ti suggerisco di usare DettaglioFattureVendita.

Te lo dico perché un codice poco comprensibile diventa difficile da leggere. Tu oggi lo sviluppi seguendo regole TUE. Se un domani dovrai riaprire questo codice o se volesse modificarlo qualcun’altro, non capirà che cosa ha in mano. Ho provato a riscrivere il tuo codice, ma non comprendendo la semantica del tuo codice, non sono in grado di suggerirti delle modifiche.

Perdonami.

Facciamo un ultimo tentativo perchè mi sembra strano non trovare una soluzione ad un problema così banale.

Stiamo su una sintassi generica in modo tale da non rischiare confusione:

tabella ‘a’ HAS MANY tabella ‘b’ su una FK id che è PK di ‘a’

In PHP faccio un banale join del tipo:


$query=SELECT * FROM a,b WHERE a.id=b.id;

La variabile risultante dal fetch di questa query è una matrice le cui colonne sono tutte quelle risultanti dal join e i valori tutti quelli che soddisfano la condizione a.id=b.id

Con Yii,

ho generato i modelli delle due tabelle con gii.

In ‘a’ ho definito una relazione di questo tipo:


'b' => array(self::HAS_MANY,'b','id'),

Nel controller di ‘a’ sfrutto l’eager loading approach:


$var=a:model()->with('b')->findAll();

In questo modo il join viene performato immediatamente così come descritto nella guida grazie al metodo with().

Ora l’unica cosa che ti chiedo è, secondo te cosa è contenuto nella variabile $var e come lo vado a leggere

per avere accesso a tutti i campi del join.

Grazie sensorario per il tempo dedicatomi, non voglio fartene perdere altro.

Se trovo una soluzione bene, altrimenti tornerò al classico PHP.

Gianlu

Tu stai confondendo le viste con le join e con l’Active Record. La join non ti da una tabella unica. Provo a spiegarmi meglio.

Se nel database ho una tabella che si chiama "tbl_utenti", di conseguenza avrò un model che si chiamerà "Utenti". Se devo caricare tutti gli utenti scrivo questo:


$utenti = Utenti::model()->findAll();



Ed avrò nella variabile $utenti, tutti i record. Ma ti ricordo che non stiamo usando sql quindi nel vecchio php avremmo scritto:


while($record = mysql_fetch_array($result)) {

    echo $record['nome];

}

Siccome con yii abbiamo a che fare con un altro pattern, possiamo scrivere questo:


foreach($utenti as $utente) {

    echo $utente->nome;

}

Quindi abbiamo degli oggetti, e non più degli array.

Tu ti sei scontrato in una chiave esterna. Supponiamo che la chiave esterna, per gli utenti, sia "indirizzo". A questo punto avremo una relazione dentro al model.


foreach($utenti as $utente) {

    echo $utente->indirizzo->via;

}

Ma se è così semplice, ti dirai, come mai io devo scorrere un array?

Devi scorrere un array perchè la relazione che hai inserito è HAS_MANY ed è corretto che sia così. Ma io non comprendo perché ti sembri così strano.

Il ragionamento è molto chiaro. Credo di aver capito il funzionamento.

Il problema è che tu scrivi di fare così:


foreach($utenti as $utente) {

    echo $utente->indirizzo->via;

}

ma


$utente->indirizzo

è a sua volta un array di oggetti, per cui non posso accedere direttamente alla proprietà ‘via’ con quella sintassi,

devo ciclare di nuovo. Ed è questo che mi fa strano: possibile che debba fare due foreach per accede ad un campo?

Se poi la risposta è SI mi metto il cuore in pace e lo faccio =)

Se è un HAS_MANY (questa relazione ha molti record) si: hai bisogno del foreach.

Se è un BELONGS_TO (il valore è chiave esterna) no: in questo caso vale il mio codice.

Mi metto il cuore in pace allora!!

Senza yii come faresti?