Domanda

Ho un app in cui molti dei modelli sono collegate da Associazioni / belongsTo hasMany. Così, per esempio, A hasMany B, B hasMany C, C hasMany D, e D hasMany E. Inoltre, E appartiene a D, D appartiene a C, C appartiene a B e B appartiene ad A. Utilizzando il comportamento contenibile è stata grande per controllare la quantità di informazioni torna con ogni query, ma mi sembra di avere un problema quando si cerca di ottenere i dati dalla tabella a durante l'utilizzo di una condizione che coinvolge tabella D. per esempio, ecco un esempio della mia 'a' modello:

class A extends AppModel {
    var $name = 'A';

    var $hasMany = array(
        'B' => array('dependent' => true)
    );

    function findDependentOnE($condition) {
        return $this->find('all', array(
            'contain' => array(
                'B' => array(
                    'C' => array(
                        'D' => array(
                            'E' => array(
                                'conditions' => array(
                                    'E.myfield' => $some_value
                                )
                            )
                        )
                    )
                )
            )
        ));
    }
}

Questo mi dà ancora indietro tutti i record in 'A', e se è legato 'E' record non soddisfano la condizione, allora ottengo solo questo:

Array(
    [0] => array(
        [A] => array(
            [field1] => // stuff
            [field2] => // more stuff
            // ...etc
        ),
        [B] => array(
            [field1] => // stuff
            [field2] => // more stuff
            // ...etc
        ),
        [C] => array(
            [field1] => // stuff
            [field2] => // more stuff
            // ...etc
        ),
        [D] => array(
            [field1] => // stuff
            [field2] => // more stuff
            // ...etc
        ),
        [E] => array( 
            // empty if 'E.myfield' != $some_value'
        )
    ),
    [1] => array( // ...etc )
)

Quando Se 'E.myfield'! = $ Some_value, non voglio il record restituito a tutti.

Spero che questo esprime il mio problema in modo sufficientemente chiaro ...

In sostanza, voglio la seguente query, ma in un database agnostico / CakePHP-y tipo di strada:

SELECT * 
FROM A INNER JOIN
        (B INNER JOIN 
            (C INNER JOIN 
                (D INNER JOIN 
                    E ON D.id=E.d_id) 
                ON C.id=D.c_id) 
            ON B.id=C.b_id) 
        ON A.id=B.a_id 
    WHERE E.myfield = $some_value
È stato utile?

Soluzione

Il tuo problema è un equivoco di ciò che il comportamento contenibile fa e ciò che l'opzione contain fa in Model::find. La chiamata Model::find nel primo codice di esempio-si tradurrebbe grosso modo:

  

Trova tutti A; poi trovare tutti i B associato ad ogni A; poi trovare tutti i C associata a ciascun B; poi trovare tutte D associata a ciascun C; infine, trovare tutte e associata a ciascun D dove un campo in E corrisponde a un valore specificato.

La dichiarazione condizione filtra solo i risultati di D, non all'altezza della catena a C, poi B, poi R. Se si esegue la scansione del registro di SQL, si vedrà un numero enorme di query tirando fuori ogni livello della catena di contain.

Al fine di ottenere CakePHP per restituire i risultati come si desidera, direttamente dalla banca dati, che avrebbe dovuto configurare un'associazione hasOne tra A e E. Con una lunga catena, come lei descrive, questo potrebbe essere abbastanza ingombrante. Sarebbe sembrare qualcosa di simile (leggi: non testata):

$this->bindModel(array('hasOne'=>array(
    'B'=>array(
        'foreignKey' => false,
        'conditions' => array('A.id = B.a_id')
    ),
    'C'=>array(
        'foreignKey' => false,
        'conditions' => array('B.id = C.b_id')
    ),
    'D'=>array(
        'foreignKey' => false,
        'conditions' => array('C.id = D.c_id')
    ),
    'E'=>array(
        'foreignKey' => false,
        'conditions' => array('D.id = E.d_id')
    )
)));

$this->find('all', array(
    'conditions' => array( 'E.my_field' => $some_value )
));

Un'alternativa è di eliminare la condizione E.my_value interamente dalla chiamata Model::find, e invece eseguire un Set::extract abbastanza complesso alla fine:

$results = $this->find('all', array(
    'contain' => array(
        'B' => array(
            'C' => array(
                'D' => array(
                    'E' => array()
                )
            )
        )
    )
));
return Set::extract("/A/B/C/D/E[my_field={$some_value}]/../../../../", $results);

Performance sarebbe un vero problema con un Set::extract profondo, però, soprattutto se si stesse operando su un sacco di righe.

Modifica : voglio solo sottolineare quanto sia terribile l'idea l'opzione Set::extract è se questa operazione ha bisogno di scala. Si sposta il intero onere di filtraggio dal motore di database sulle funzioni di array di PHP.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top