2012-05-05 14 views
6

Ho una relazione molti-a-molti, implementata con una tabella di associazioni in MySQL. Ho un tavolo per bambini e un tavolo per i genitori. Un bambino può avere più genitori, salvati nella tabella di associazione parent_child_link con i rispettivi ID.Aggiornamento PHP Relazione molti-a-molti MYSQL

I bambini possono essere aggiornati tramite un modulo HTML, i genitori sono in una multi-selezione HTML. Ora ho bisogno di aggiornare il record nel database, ma la mia soluzione non è molto efficiente. Ecco in pseudocodice quello che faccio:

  1. Aggiornare le informazioni bambino dove child_id = x
  2. eliminare tutte le associazioni attuali parent_child_link dove child_id = x
  3. Inserire le nuove associazioni

Questa soluzione funziona alla grande, ma quando i genitori non sono stati cambiati, ad es è stato modificato solo il nome del bambino, quindi sono state eseguite 2 query non necessarie. Come posso evitare queste query inutili? C'è un modo per verificare se i genitori nella selezione multipla non sono cambiati?

Ovviamente potrei semplicemente ignorare tutto questo fastidio, perché funziona già, ma mi piace davvero mantenere le cose il più efficienti possibile.

risposta

0

Provare a risolverlo nel database, non nel livello applicazione utilizzando ON UPDATE CASCADE e ON DELETE CASCADE nella definizione della tabella figlio.

Un esempio leggermente rivisto formare il sito di MySQL:

CREATE TABLE parent (id INT NOT NULL, 
        PRIMARY KEY (id) 
) ENGINE=INNODB; 

CREATE TABLE child (id INT, parent_id INT, 
        INDEX par_ind (parent_id), 
        FOREIGN KEY (parent_id) REFERENCES parent(id) 
         ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=INNODB; 

Scopri i documenti qui: http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html

EDIT: Per la vostra molti-a-molti relazione si può usare qualcosa di simile a:

CREATE TABLE parent_child_link (
        parent_id INT NOT NULL, 
        child_id INT NOT NULL, 
        PRIMARY KEY(parent_id, child_id), 
        FOREIGN KEY (parent_id) REFERENCES parent(id) 
         ON DELETE CASCADE ON UPDATE CASCADE, 
        FOREIGN KEY (child_id) REFERENCES child(id) 
         ON DELETE CASCADE ON UPDATE CASCADE 
); 

Spero che questo aiuti.

+0

Questo è uno-a-uno; L'OP ha una relazione molti-a-molti con una tabella pivot. – lafor

+0

La tua giusta lafor, mia cattiva. –

+1

Mi piacerebbe spostarlo al di fuori del livello dell'applicazione, ma non vedo come la soluzione con i riferimenti possa risolvere il mio problema. Per quanto sono riuscito ad analizzarlo, sarebbe utile quando si elimina un bambino o un genitore (per sbarazzarsi del link). – EsTeGe

0

La soluzione è a posto.
Nel tuo caso potresti "ottimizzare" il processo facendo una query per recuperare i genitori e verificare con i dati di selezione multipla se si sono verificati cambiamenti.
Quindi si eseguono solo le due eliminazioni e si inseriscono le query se necessario. La controparte è che quando hai effettivamente cambiato i genitori, ci saranno 3 query invece di 2.
Quindi dovresti chiederti se stai modificando i genitori molto spesso. In questo caso, è necessario attenersi alla soluzione originale per evitare una query di selezione aggiuntiva.
Se pensi che i genitori non saranno aggiornati molto spesso, allora puoi andare con la soluzione di cui sopra. Quando aggiorni solo le informazioni secondarie, viene eseguita una sola query. Quando aggiorni anche i genitori, vengono eseguite 3 query.
Quando si utilizza la seconda soluzione, anche le query delete e insert possono essere ottimizzate per eseguire solo ciò che è necessario (eliminare solo i genitori che non sono più i suoi genitori e inserire solo nuovi collegamenti padre).
Le funzioni di array PHP possono essere utili per questo.

0

Se si desidera mantenere l'attuale modo di farlo, ma solo ottimizzando, è possibile racchiudere le query nelle istruzioni IF.

come:

if (isset ($parent_name_change)){ // run query }

7

Ho la stessa domanda e capito la mia soluzione come stavo leggendo.

Quando sono pronto per elaborare le voci inviate, prima faccio una query per ottenere le associazioni correnti e chiamare quella matrice $ lista_originale. L'elenco inviato chiamerò $ submitted_list.

$original_list = array(3,5,7); 
$submitted_list = array(1,2,3); 

Poi ho solo bisogno di capire 1) gli elementi da cancellare (non esistono più) e 2) che i prodotti da aggiungere (nuove associazioni). Gli articoli in entrambi gli elenchi non vengono toccati.

$delete_list = array_diff($original_list, $submitted_list); 
$insert_list = array_diff($submitted_list, $original_list); 

foreach($delete_list as $item) { 
    // delete $item from DB 
} 

foreach($insert_list as $item) { 
    // insert item in db 
} 

Mi piacerebbe sapere se altri ritengono che questa sia una soluzione valida.

+1

sì, questo è il modo in cui ho fatto cose simili in passato. normalmente andrei con l'approccio delta -> insert ma questo può essere un problema se l'ID dei bambini viene referenziato altrove, come ad esempio se si aggiungono più voci di prezzo a un prodotto e l'ID prezzo è referenziato dal carrello . non posso andare a cambiare gli ID quando i prezzi tecnicamente non sono cambiati. – jammypeach