2012-12-05 8 views
9

Sto utilizzando il pattern Data Mapper e mi chiedo quale sia il modo migliore per gestire le relazioni con tale modello. Ho passato molto tempo a cercare soluzioni in Google e l'overflow dello stack, ne ho trovato alcuni, ma non ne sono ancora completamente soddisfatto, specialmente in un caso speciale che cercherò di spiegare.Gestione delle relazioni con il pattern Data Mapper

Sto lavorando con PHP, quindi gli esempi di codice che inserirò sono in PHP.

Diciamo che ho una tabella "squadra" (id, nome) e una tabella "player" (id, nome, team_id). Questa è una relazione 1-N. Implementando il pattern Data Mapper, avremo le seguenti classi: Team, TeamMapper, Player e PlayerMapper.

Finora tutto è semplice. Cosa succede se vogliamo ottenere tutti i giocatori da una squadra?

La prima soluzione che ho trovato è creare un metodo getAllPlayers() nella classe Team che gestirà quello con il lazy loading e i proxy. Poi, siamo in grado di recuperare i giocatori di una squadra del genere:

$players = $team->getAllPlayers(); 

La seconda soluzione che ho trovato è quello di utilizzare direttamente il PlayerMapper e passare l'ID squadra come parametro. Qualcosa di simile:

$playerMapper->findAll(array('team_id' => $team->getId())); 

Ma ora, diciamo che voglio visualizzare una tabella HTML con tutti i team e con una colonna 'giocatori con tutti i giocatori di ogni squadra. Se usiamo la prima soluzione che ho descritto, dovremo fare una query SQL per ottenere l'elenco di squadre e una query per ogni squadra per ottenere i giocatori, il che significa N + 1 query SQL dove N è il numero di squadre.

Se usiamo le seconde soluzioni che ho descritto, possiamo prima di recuperare tutti gli ID di squadra, metterli in un array, e poi passarlo al metodo findAll del giocatore mapper, qualcosa di simile:

$playerMapper->findAll(array('team_id' => $teamIds)); 

In tal caso, è necessario eseguire solo 2 query. Molto meglio. Ma non sono ancora molto contento di questa soluzione perché le relazioni non sono descritte nei modelli ed è lo sviluppatore che deve conoscerle.

Quindi la mia domanda è: ci sono altre alternative con il pattern Data Mapper? Con l'esempio che ho dato, c'è un buon modo per selezionare tutte le squadre con tutti i giocatori in sole 2 query con la descrizione delle relazioni nel modello?

Grazie in anticipo!

risposta

2

Se osservate il testo di Martin Fowler che descrive come funziona DataMapper, vedrete che è possibile utilizzare una query per ottenere tutti i dati necessari e quindi passare tali dati a ciascun mappatore, consentendo al mappatore di selezionare solo i dati di cui ha bisogno.

Per te, questa sarebbe una query che si collega da Team a Player, restituendo un set di risultati con dati del team duplicati per ciascun Player univoco.

È quindi necessario provvedere alla duplicazione nel codice di mapping creando solo nuovi oggetti quando i dati cambiano.

Ho fatto qualcosa di simile in cui l'equivalente sarebbe l'iterazione squadra mapper sul set di risultati e, per ogni squadra unica passare il set di risultati per il mapper lettore in modo che possa creare un giocatore e quindi aggiungere il giocatore a la collezione del team.

Anche se questo funzionerà, ci sono problemi con questo approccio più a valle ...

+0

A quale testo di Martin Fowler fa riferimento? L'unico che ho trovato è quello (http://www.martinfowler.com/eaaCatalog/dataMapper.html) e non vedo nulla di quello che dici. Ad ogni modo, questo approccio non mi convince. Significa che devi eseguire una query restituendo righe NxM (con N il numero di team e M il numero di giocatori) con molti dati duplicati. E significa anche mappare i giocatori attraverso il mappatore Team che non suona così bene. E come hai detto, sono sicuro che ci sono problemi con questo approccio più a valle ... – Vincent

+0

È nel libro del PoA. Il sito Web fornisce solo una panoramica. La tua query non restituisce righe NxM, solo righe M. Porta indietro molti dati, ma questo è il punto. Afferra il più possibile in un round trip. Inoltre, il tuo mappatore del team non mappa i giocatori, chiede al giocatore mappatore di mappare i giocatori per questo. –

+0

Sì, mi dispiace, M righe. Bene, questa è una soluzione, ma non sono ancora completamente convinto. Vediamo se la mia domanda porterà più risposte ... – Vincent

0

Ho una possibile soluzione a questo problema che ho implementato con successo in uno dei miei progetti. Non è così complesso e userebbe solo 2 query nell'esempio sopra descritto.

La soluzione è aggiungere un altro livello di codice responsabile della gestione delle relazioni.

Per esempio, possiamo metterlo in una classe di servizio (che può essere usata anche per altre cose, non solo per gestire le relazioni). Quindi diciamo che abbiamo un TeamService di classe in cima a Team e TeamMapper. TeamService avrebbe un metodo getTeamsWithRelationships() che restituirebbe una matrice di oggetti Team. getTeamsWithRelationships() usa TeamMapper per ottenere l'elenco dei team. Quindi, con PlayerMapper, otterrebbe in una sola query l'elenco dei giocatori per questi team e imposta i giocatori ai team usando un metodo setPlayers() dalla classe Team.

Questa soluzione è abbastanza semplice e facile da implementare e funziona bene per tutti i tipi di relazioni tra database. Immagino che alcune persone potrebbero avere qualcosa in contrario. Se è così, sarei interessato a sapere quali sono i problemi?