Εξερεύνηση βάσης δεδομένων
Η Εξερεύνηση προσφέρει έναν διαισθητικό και αποτελεσματικό τρόπο εργασίας με τη βάση δεδομένων σας. Χειρίζεται αυτόματα τις σχέσεις μεταξύ των πινάκων, δημιουργεί βελτιστοποιημένα ερωτήματα και σας επιτρέπει να επικεντρωθείτε στη λογική της εφαρμογής σας. Δεν απαιτείται διαμόρφωση. Για πλήρη έλεγχο μπορείτε να μεταβείτε στον τρόπο SQL.
- Η εργασία με τα δεδομένα είναι φυσική και εύκολα κατανοητή
- Δημιουργεί βελτιστοποιημένα ερωτήματα SQL που αντλούν μόνο τα απαραίτητα δεδομένα
- Παρέχει εύκολη πρόσβαση σε συναφή δεδομένα χωρίς την ανάγκη συγγραφής ερωτημάτων JOIN
- Λειτουργεί άμεσα χωρίς καμία διαμόρφωση ή δημιουργία οντοτήτων
Η εργασία με την Εξερεύνηση ξεκινά με την κλήση της μεθόδου
table()
στο αντικείμενο Nette\Database\Explorer (για
λεπτομέρειες σχετικά με τη ρύθμιση της σύνδεσης με τη βάση δεδομένων,
ανατρέξτε στην ενότητα Σύνδεση και
διαμόρφωση ):
Η μέθοδος επιστρέφει ένα αντικείμενο Selection, το οποίο αναπαριστά
ένα ερώτημα SQL. Πρόσθετες μέθοδοι μπορούν να συνδεθούν αλυσιδωτά με
αυτό το αντικείμενο για το φιλτράρισμα και την ταξινόμηση των
αποτελεσμάτων. Το ερώτημα συναρμολογείται και εκτελείται μόνο όταν
ζητούνται τα δεδομένα, για παράδειγμα, με επανάληψη με το foreach
.
Κάθε γραμμή αντιπροσωπεύεται από ένα αντικείμενο ActiveRow:
Η Εξερεύνηση απλοποιεί σημαντικά την εργασία με τις σχέσεις πινάκων. Το ακόλουθο παράδειγμα δείχνει πόσο εύκολα μπορούμε να εξάγουμε δεδομένα από σχετικούς πίνακες (βιβλία και οι συγγραφείς τους). Παρατηρήστε ότι δεν χρειάζεται να γράψετε κανένα ερώτημα JOIN- η Nette τα παράγει για εμάς:
Η Nette Database Explorer βελτιστοποιεί τα ερωτήματα για μέγιστη αποδοτικότητα. Το παραπάνω παράδειγμα εκτελεί μόνο δύο ερωτήματα SELECT, ανεξάρτητα από το αν επεξεργαζόμαστε 10 ή 10.000 βιβλία.
Επιπλέον, ο Explorer παρακολουθεί ποιες στήλες χρησιμοποιούνται στον κώδικα και αντλεί μόνο αυτές από τη βάση δεδομένων, εξοικονομώντας περαιτέρω απόδοση. Αυτή η συμπεριφορά είναι πλήρως αυτόματη και προσαρμοστική. Αν αργότερα τροποποιήσετε τον κώδικα για να χρησιμοποιήσετε επιπλέον στήλες, ο Explorer προσαρμόζει αυτόματα τα ερωτήματα. Δεν χρειάζεται να ρυθμίσετε τίποτα ή να σκεφτείτε ποιες στήλες θα χρειαστούν – αφήστε το στη Nette.
Φιλτράρισμα και ταξινόμηση
Η κλάση Selection
παρέχει μεθόδους φιλτραρίσματος και ταξινόμησης
δεδομένων.
where($condition, ...$params) |
Προσθέτει μια συνθήκη WHERE. Οι πολλαπλές συνθήκες συνδυάζονται με τη χρήση AND |
whereOr(array $conditions) |
Προσθέτει μια ομάδα συνθηκών WHERE που συνδυάζονται με τη χρήση OR |
wherePrimary($value) |
Προσθέτει μια συνθήκη WHERE με βάση το πρωτεύον κλειδί |
order($columns, ...$params) |
Ορίζει ταξινόμηση με ORDER BY |
select($columns, ...$params) |
Καθορίζει ποιες στήλες θα αντληθούν |
limit($limit, $offset = null) |
Περιορίζει τον αριθμό των γραμμών (LIMIT) και προαιρετικά ορίζει OFFSET |
page($page, $itemsPerPage, &$total = null) |
Ορίζει σελιδοποίηση |
group($columns, ...$params) |
Ομαδοποιεί σειρές (GROUP BY) |
having($condition, ...$params) |
Προσθέτει μια συνθήκη HAVING για το φιλτράρισμα των ομαδοποιημένων γραμμών |
Οι μέθοδοι μπορούν να αλυσιδωθούν (η λεγόμενη ρευστή
διεπαφή): $table->where(...)->order(...)->limit(...)
.
Αυτές οι μέθοδοι επιτρέπουν επίσης τη χρήση ειδικών συμβολισμών για την πρόσβαση σε δεδομένα από σχετικούς πίνακες.
Διαφυγή και αναγνωριστικά
Οι μέθοδοι αποφεύγουν αυτόματα τις παραμέτρους και τα αναγνωριστικά παραθέματος (ονόματα πινάκων και στηλών), αποτρέποντας την έγχυση SQL. Για να διασφαλιστεί η σωστή λειτουργία, πρέπει να τηρούνται μερικοί κανόνες:
- Γράψτε λέξεις-κλειδιά, ονόματα συναρτήσεων, διαδικασίες, κ.λπ., σε uppercase.
- Γράψτε τα ονόματα στηλών και πινάκων με μικρά γράμματα.
- Πάντα να περνάτε συμβολοσειρές χρησιμοποιώντας παραμέτρους.
where(string|array $condition, …$parameters): static
Φιλτράρει τα αποτελέσματα χρησιμοποιώντας συνθήκες WHERE. Η δύναμή του έγκειται στον έξυπνο χειρισμό διαφόρων τύπων τιμών και στην αυτόματη επιλογή τελεστών SQL.
Βασική χρήση:
Χάρη στην αυτόματη ανίχνευση των κατάλληλων χειριστών, δεν χρειάζεται να χειρίζεστε ειδικές περιπτώσεις – η Nette τις χειρίζεται για εσάς:
Η μέθοδος χειρίζεται επίσης σωστά τις αρνητικές συνθήκες και τους άδειους πίνακες:
Μπορείτε επίσης να περάσετε το αποτέλεσμα ενός άλλου ερωτήματος πίνακα ως παράμετρο, δημιουργώντας ένα υποερώτημα:
Οι συνθήκες μπορούν επίσης να περάσουν ως πίνακας, με τα στοιχεία να συνδυάζονται με τη χρήση AND:
Στον πίνακα μπορούν να χρησιμοποιηθούν ζεύγη κλειδιών-τιμών και η Nette θα επιλέξει και πάλι αυτόματα τους σωστούς τελεστές:
Μπορούμε επίσης να αναμειγνύουμε εκφράσεις SQL με placeholders και πολλαπλές παραμέτρους. Αυτό είναι χρήσιμο για σύνθετες συνθήκες με επακριβώς καθορισμένους τελεστές:
Πολλαπλές κλήσεις στο where()
συνδυάζουν αυτόματα τις συνθήκες
με τη χρήση AND.
whereOr(array $parameters): static
Παρόμοιο με το where()
, αλλά συνδυάζει τις συνθήκες
χρησιμοποιώντας OR:
Μπορούν επίσης να χρησιμοποιηθούν πιο σύνθετες εκφράσεις:
wherePrimary(mixed $key): static
Προσθέτει μια συνθήκη για το πρωτεύον κλειδί του πίνακα:
(π.χ. foo_id
, bar_id
), το περνάμε ως πίνακα:
order(string $columns, …$parameters): static
Καθορίζει τη σειρά με την οποία επιστρέφονται οι γραμμές. Μπορείτε να ταξινομήσετε με βάση μία ή περισσότερες στήλες, με αύξουσα ή φθίνουσα σειρά ή με βάση μια προσαρμοσμένη έκφραση:
select(string $columns, …$parameters): static
Καθορίζει τις στήλες που θα επιστραφούν από τη βάση δεδομένων. Από
προεπιλογή, η Nette Database Explorer επιστρέφει μόνο τις στήλες που
χρησιμοποιούνται πραγματικά στον κώδικα. Χρησιμοποιήστε τη μέθοδο
select()
όταν πρέπει να ανακτήσετε συγκεκριμένες εκφράσεις:
Τα ψευδώνυμα που ορίζονται με τη χρήση του AS
είναι στη
συνέχεια προσβάσιμα ως ιδιότητες του αντικειμένου ActiveRow
:
limit(?int $limit, ?int $offset = null): static
Περιορίζει τον αριθμό των επιστρεφόμενων γραμμών (LIMIT) και προαιρετικά ορίζει μια μετατόπιση:
Για σελιδοποίηση, είναι καταλληλότερο να χρησιμοποιείτε τη μέθοδο
page()
.
page(int $page, int $itemsPerPage, &$numOfPages = null): static
Απλοποιεί την σελιδοποίηση των αποτελεσμάτων. Δέχεται τον αριθμό σελίδας (ξεκινώντας από το 1) και τον αριθμό των στοιχείων ανά σελίδα. Προαιρετικά, μπορείτε να περάσετε μια αναφορά σε μια μεταβλητή όπου θα αποθηκευτεί ο συνολικός αριθμός σελίδων:
group(string $columns, …$parameters): static
Ομαδοποιεί τις γραμμές με βάση τις καθορισμένες στήλες (GROUP BY). Χρησιμοποιείται συνήθως σε συνδυασμό με συναρτήσεις συνάθροισης:
having(string $having, …$parameters): static
Ορίζει μια συνθήκη για το φιλτράρισμα ομαδοποιημένων γραμμών (HAVING).
Μπορεί να χρησιμοποιηθεί σε συνδυασμό με τη μέθοδο group()
και τις
συναρτήσεις συνάθροισης:
Ανάγνωση δεδομένων
Για την ανάγνωση δεδομένων από τη βάση δεδομένων, υπάρχουν αρκετές χρήσιμες μέθοδοι:
foreach ($table as $key => $row) |
Επαναλαμβάνει όλες τις γραμμές, $key είναι η τιμή του
πρωτεύοντος κλειδιού, $row είναι ένα αντικείμενο ActiveRow |
$row = $table->get($key) |
Επιστρέφει μία μόνο γραμμή με βάση το πρωτεύον κλειδί |
$row = $table->fetch() |
Επιστρέφει την τρέχουσα γραμμή και προωθεί τον δείκτη στην επόμενη |
$array = $table->fetchPairs() |
Δημιουργεί έναν συσχετιστικό πίνακα από τα αποτελέσματα |
$array = $table->fetchAll() |
Επιστρέφει όλες τις γραμμές ως πίνακα |
count($table) |
Επιστρέφει τον αριθμό των γραμμών στο αντικείμενο Selection |
Το αντικείμενο ActiveRow είναι μόνο για ανάγνωση. Αυτό σημαίνει ότι δεν μπορείτε να αλλάξετε τις τιμές των ιδιοτήτων του. Αυτός ο περιορισμός διασφαλίζει τη συνοχή των δεδομένων και αποτρέπει απροσδόκητες παρενέργειες. Τα δεδομένα αντλούνται από τη βάση δεδομένων και οποιεσδήποτε αλλαγές θα πρέπει να γίνονται ρητά και με ελεγχόμενο τρόπο.
foreach
– Επανάληψη όλων των σειρών
Ο ευκολότερος τρόπος εκτέλεσης ενός ερωτήματος και ανάκτησης
γραμμών είναι η επανάληψη με τον βρόχο foreach
. Εκτελεί αυτόματα το
ερώτημα SQL.
get($key): ?ActiveRow
Εκτελεί ένα ερώτημα SQL και επιστρέφει μια γραμμή με βάση το πρωτεύον
κλειδί της ή το null
εάν δεν υπάρχει.
fetch(): ?ActiveRow
Επιστρέφει μια γραμμή και προωθεί τον εσωτερικό δείκτη στην επόμενη.
Εάν δεν υπάρχουν άλλες γραμμές, επιστρέφει null
.
fetchPairs(string|int|null $key = null, string|int|null $value = null): array
Επιστρέφει τα αποτελέσματα ως συσχετιστικό πίνακα. Το πρώτο όρισμα καθορίζει το όνομα της στήλης που θα χρησιμοποιηθεί ως κλειδί του πίνακα και το δεύτερο όρισμα καθορίζει το όνομα της στήλης που θα χρησιμοποιηθεί ως τιμή:
Εάν παρέχεται μόνο η πρώτη παράμετρος, ολόκληρη η σειρά θα
χρησιμοποιηθεί ως τιμή, η οποία αναπαρίσταται ως αντικείμενο
ActiveRow
:
Σε περίπτωση διπλών κλειδιών, χρησιμοποιείται η τιμή της τελευταίας
γραμμής. Όταν χρησιμοποιείται το null
ως κλειδί, ο πίνακας θα
δεικτοδοτείται αριθμητικά από το μηδέν (οπότε δεν προκύπτουν
συγκρούσεις):
fetchPairs(Closure $callback): array
Εναλλακτικά, μπορείτε να περάσετε ένα callback ως παράμετρο. Το callback θα εφαρμοστεί σε κάθε γραμμή για να επιστρέψει είτε μια απλή τιμή είτε ένα ζεύγος κλειδιού-τιμής.
fetchAll(): array
Επιστρέφει όλες τις γραμμές ως συσχετιστικό πίνακα αντικειμένων
ActiveRow
, όπου τα κλειδιά είναι οι τιμές του πρωτεύοντος
κλειδιού.
count(): int
Η μέθοδος count()
χωρίς παραμέτρους επιστρέφει τον αριθμό των
γραμμών στο αντικείμενο Selection
:
Σημείωση: Η μέθοδος count()
με μια παράμετρο εκτελεί τη
λειτουργία συνάθροισης COUNT στη βάση δεδομένων, όπως περιγράφεται
παρακάτω.
ActiveRow::toArray(): array
Μετατρέπει το αντικείμενο ActiveRow
σε συσχετιστικό πίνακα όπου
τα κλειδιά είναι ονόματα στηλών και οι τιμές είναι τα αντίστοιχα
δεδομένα.
Συγκέντρωση
Η κλάση Selection
παρέχει μεθόδους για την εύκολη εκτέλεση
συναρτήσεων άθροισης (COUNT, SUM, MIN, MAX, AVG, κ.λπ.).
count($expr) |
Μετράει τον αριθμό των γραμμών |
min($expr) |
Επιστρέφει την ελάχιστη τιμή σε μια στήλη |
max($expr) |
Επιστρέφει τη μέγιστη τιμή σε μια στήλη |
sum($expr) |
Επιστρέφει το άθροισμα των τιμών σε μια στήλη |
aggregation($function) |
Επιτρέπει οποιαδήποτε συνάρτηση άθροισης, όπως AVG()
ή GROUP_CONCAT() |
count(string $expr): int
Εκτελεί ένα ερώτημα SQL με τη συνάρτηση COUNT και επιστρέφει το αποτέλεσμα. Αυτή η μέθοδος χρησιμοποιείται για να προσδιοριστεί πόσες γραμμές αντιστοιχούν σε μια συγκεκριμένη συνθήκη:
Σημείωση: η count() χωρίς παράμετρο επιστρέφει απλώς τον
αριθμό των γραμμών στο αντικείμενο Selection
.
min(string $expr) and max(string $expr)
Οι μέθοδοι min()
και max()
επιστρέφουν την ελάχιστη και τη
μέγιστη τιμή στην καθορισμένη στήλη ή έκφραση:
sum(string $expr): int
Επιστρέφει το άθροισμα των τιμών στην καθορισμένη στήλη ή έκφραση:
aggregation(string $function, ?string $groupFunction = null): mixed
Επιτρέπει την εκτέλεση οποιασδήποτε συνάρτησης άθροισης.
Εάν χρειάζεται να αθροίσουμε αποτελέσματα που τα ίδια προκύπτουν από
μια συνάθροιση και ομαδοποίηση (π.χ. SUM(value)
πάνω σε
ομαδοποιημένες γραμμές), καθορίζουμε τη συνάρτηση συνάθροισης που θα
εφαρμοστεί σε αυτά τα ενδιάμεσα αποτελέσματα ως δεύτερο όρισμα:
Σε αυτό το παράδειγμα, υπολογίζουμε πρώτα τη συνολική τιμή των
προϊόντων σε κάθε κατηγορία (SUM(price * stock) AS category_total
) και
ομαδοποιούμε τα αποτελέσματα με βάση το category_id
. Στη συνέχεια
χρησιμοποιούμε το aggregation('SUM(category_total)', 'SUM')
για να αθροίσουμε αυτά
τα επιμέρους αθροίσματα. Το δεύτερο όρισμα 'SUM'
καθορίζει τη
συνάρτηση άθροισης που θα εφαρμοστεί στα ενδιάμεσα αποτελέσματα.
Εισαγωγή, ενημέρωση και διαγραφή
Η Nette Database Explorer απλοποιεί την εισαγωγή, την ενημέρωση και τη διαγραφή
δεδομένων. Όλες οι αναφερόμενες μέθοδοι πετούν ένα
Nette\Database\DriverException
σε περίπτωση σφάλματος.
Selection::insert(iterable $data): static
Εισάγει νέες εγγραφές σε έναν πίνακα.
Εισαγωγή μίας μόνο εγγραφής:
Η νέα εγγραφή παραδίδεται ως συσχετιστικός πίνακας ή αντικείμενο
επανάληψης (όπως το ArrayHash
που χρησιμοποιείται στις φόρμες), όπου τα κλειδιά αντιστοιχούν στα ονόματα
των στηλών του πίνακα.
Εάν ο πίνακας έχει καθορισμένο πρωτεύον κλειδί, η μέθοδος επιστρέφει
ένα αντικείμενο ActiveRow
, το οποίο φορτώνεται εκ νέου από τη βάση
δεδομένων για να αντικατοπτρίζει τυχόν αλλαγές που έγιναν σε επίπεδο
βάσης δεδομένων (π.χ. εναύσματα, προεπιλεγμένες τιμές στηλών ή
υπολογισμούς αυτόματης αύξησης). Αυτό διασφαλίζει τη συνέπεια των
δεδομένων και το αντικείμενο περιέχει πάντα τα τρέχοντα δεδομένα της
βάσης δεδομένων. Εάν δεν έχει οριστεί ρητά ένα πρωτεύον κλειδί, η
μέθοδος επιστρέφει τα δεδομένα εισόδου ως πίνακα.
Εισαγωγή πολλαπλών εγγραφών ταυτόχρονα:
Η μέθοδος insert()
σας επιτρέπει να εισάγετε πολλαπλές εγγραφές
με ένα μόνο ερώτημα SQL. Σε αυτή την περίπτωση, επιστρέφει τον αριθμό των
εισαγόμενων γραμμών.
Μπορείτε επίσης να περάσετε ως παράμετρο ένα αντικείμενο
Selection
με μια επιλογή δεδομένων.
Εισαγωγή ειδικών τιμών:
Οι τιμές μπορούν να περιλαμβάνουν αρχεία, αντικείμενα DateTime
ή
λογοτεχνικά στοιχεία SQL:
Selection::update(iterable $data): int
Ενημερώνει γραμμές σε έναν πίνακα με βάση ένα καθορισμένο φίλτρο. Επιστρέφει τον αριθμό των σειρών που τροποποιήθηκαν πραγματικά.
Οι προς ενημέρωση στήλες περνούν ως συσχετιστικός πίνακας ή
αντικείμενο επανάληψης (όπως το ArrayHash
που χρησιμοποιείται στις
φόρμες), όπου τα κλειδιά αντιστοιχούν στα
ονόματα των στηλών του πίνακα:
Για να αλλάξετε αριθμητικές τιμές, μπορείτε να χρησιμοποιήσετε τους
τελεστές +=
και -=
:
Selection::delete(): int
Διαγράφει γραμμές από έναν πίνακα με βάση ένα καθορισμένο φίλτρο. Επιστρέφει τον αριθμό των διαγραμμένων γραμμών.
Κατά την κλήση των update()
ή delete()
, φροντίστε να
χρησιμοποιήσετε το where()
για να καθορίσετε τις γραμμές που θα
ενημερωθούν ή θα διαγραφούν. Εάν δεν χρησιμοποιηθεί το where()
, η
λειτουργία θα εκτελεστεί σε ολόκληρο τον πίνακα!
ActiveRow::update(iterable $data): bool
Ενημερώνει τα δεδομένα σε μια γραμμή της βάσης δεδομένων που
αντιπροσωπεύεται από το αντικείμενο ActiveRow
. Δέχεται επαναλήψιμα
δεδομένα ως παράμετρο, όπου τα κλειδιά είναι ονόματα στηλών. Για να
αλλάξετε αριθμητικές τιμές, μπορείτε να χρησιμοποιήσετε τους τελεστές
+=
και -=
:
Αφού εκτελεστεί η ενημέρωση, το ActiveRow
φορτώνεται αυτόματα εκ
νέου από τη βάση δεδομένων για να αντικατοπτρίζει τυχόν αλλαγές που
έγιναν σε επίπεδο βάσης δεδομένων (π.χ. εναύσματα). Η μέθοδος επιστρέφει
το true
μόνο εάν έχει πραγματοποιηθεί πραγματική αλλαγή
δεδομένων.
Αυτή η μέθοδος ενημερώνει μόνο μια συγκεκριμένη γραμμή στη βάση δεδομένων. Για μαζικές ενημερώσεις πολλών γραμμών, χρησιμοποιήστε τη μέθοδο Selection::update().
ActiveRow::delete()
Διαγράφει μια γραμμή από τη βάση δεδομένων που αντιπροσωπεύεται από
το αντικείμενο ActiveRow
.
Αυτή η μέθοδος διαγράφει μόνο μια συγκεκριμένη γραμμή στη βάση δεδομένων. Για μαζική διαγραφή πολλών γραμμών, χρησιμοποιήστε τη μέθοδο Selection::delete().
Σχέσεις μεταξύ πινάκων
Στις σχεσιακές βάσεις δεδομένων, τα δεδομένα χωρίζονται σε πολλούς πίνακες και συνδέονται μέσω ξένων κλειδιών. Ο Nette Database Explorer προσφέρει έναν επαναστατικό τρόπο εργασίας με αυτές τις σχέσεις – χωρίς να γράφει ερωτήματα JOIN ή να απαιτεί οποιαδήποτε διαμόρφωση ή δημιουργία οντοτήτων.
Για την επίδειξη, θα χρησιμοποιήσουμε τη βάση δεδομένων παράδειγμα(διαθέσιμη στο GitHub). Η βάση δεδομένων περιλαμβάνει τους ακόλουθους πίνακες:
author
– συγγραφείς και μεταφραστές (στήλεςid
,name
,web
,born
)book
– βιβλία (στήλεςid
,author_id
,translator_id
,title
,sequel_id
)tag
– ετικέτες (στήλεςid
,name
)book_tag
– πίνακας συνδέσμων μεταξύ βιβλίων και ετικετών (στήλεςbook_id
,tag_id
)

Δομή της βάσης δεδομένων
Σε αυτό το παράδειγμα βάσης δεδομένων βιβλίων, βρίσκουμε διάφορους τύπους σχέσεων (απλοποιημένους σε σχέση με την πραγματικότητα):
- Ένα προς πολλά (1:N) – Κάθε βιβλίο έχει έναν συγγραφέα- ένας συγγραφέας μπορεί να γράψει πολλαπλά βιβλία.
- Νέο προς πολλά (0:N) – Ένα βιβλίο μπορεί να έχει έναν μεταφραστή- ένας μεταφραστής μπορεί να μεταφράσει πολλαπλά βιβλία.
- Μηδέν προς ένα (0:1) – Ένα βιβλίο μπορεί να έχει συνέχεια.
- Πολλοί-προς-πολλούς (Μ:Ν) – Ένα βιβλίο μπορεί να έχει πολλές ετικέτες και μια ετικέτα μπορεί να ανατεθεί σε πολλά βιβλία.
Σε αυτές τις σχέσεις, υπάρχει πάντα ένας πίνακας γονέας και ένας
πίνακας παιδί. Για παράδειγμα, στη σχέση μεταξύ συγγραφέων και
βιβλίων, ο πίνακας author
είναι ο γονέας και ο πίνακας book
είναι το παιδί – μπορείτε να το φανταστείτε ότι ένα βιβλίο „ανήκει“
πάντα σε έναν συγγραφέα. Αυτό αντικατοπτρίζεται και στη δομή της βάσης
δεδομένων: ο πίνακας-παιδί book
περιέχει το ξένο κλειδί
author_id
, το οποίο παραπέμπει στον πίνακα-γονέα author
.
Αν θέλουμε να εμφανίσουμε τα βιβλία μαζί με τα ονόματα των συγγραφέων τους, έχουμε δύο επιλογές. Είτε ανακτούμε τα δεδομένα χρησιμοποιώντας ένα ενιαίο ερώτημα SQL με ένα JOIN:
Ή ανακτούμε τα δεδομένα σε δύο βήματα – πρώτα τα βιβλία, μετά τους συγγραφείς τους – και τα συναρμολογούμε σε PHP:
Η δεύτερη προσέγγιση είναι, παραδόξως, πιο αποδοτική. Τα δεδομένα ανακτώνται μόνο μία φορά και μπορούν να αξιοποιηθούν καλύτερα στην κρυφή μνήμη. Έτσι ακριβώς λειτουργεί ο Nette Database Explorer – χειρίζεται τα πάντα κάτω από την κουκούλα και σας παρέχει ένα καθαρό API:
Πρόσβαση στον γονικό πίνακα
Η πρόσβαση στον γονικό πίνακα είναι απλή. Πρόκειται για σχέσεις όπως
ένα βιβλίο έχει έναν συγγραφέα ή ένα βιβλίο μπορεί να έχει έναν
μεταφραστή. Η σχετική εγγραφή μπορεί να προσπελαστεί μέσω της
ιδιότητας του αντικειμένου ActiveRow
– το όνομα της ιδιότητας
ταιριάζει με το όνομα της στήλης του ξένου κλειδιού χωρίς την κατάληξη
id
:
Κατά την πρόσβαση στην ιδιότητα $book->author
, ο Explorer αναζητά μια
στήλη στον πίνακα book
που περιέχει τη συμβολοσειρά author
(π.χ. author_id
). Με βάση την τιμή σε αυτή τη στήλη, ανακτά την
αντίστοιχη εγγραφή από τον πίνακα author
και την επιστρέφει ως
αντικείμενο ActiveRow
. Ομοίως, το $book->translator
χρησιμοποιεί τη
στήλη translator_id
. Δεδομένου ότι η στήλη translator_id
μπορεί να
περιέχει null
, χρησιμοποιείται ο τελεστής ?->
.
Μια εναλλακτική προσέγγιση παρέχεται από τη μέθοδο ref()
, η
οποία δέχεται δύο ορίσματα – το όνομα του πίνακα-στόχου και τη στήλη
σύνδεσης – και επιστρέφει ένα αντικείμενο ActiveRow
ή null
:
Η μέθοδος ref()
είναι χρήσιμη εάν δεν μπορεί να χρησιμοποιηθεί
πρόσβαση με βάση την ιδιότητα, για παράδειγμα, όταν ο πίνακας περιέχει
μια στήλη με το ίδιο όνομα με την ιδιότητα (author
). Σε άλλες
περιπτώσεις, συνιστάται η χρήση της πρόσβασης με βάση την ιδιότητα για
καλύτερη αναγνωσιμότητα.
Ο Explorer βελτιστοποιεί αυτόματα τα ερωτήματα στη βάση δεδομένων. Κατά την επανάληψη των βιβλίων και την πρόσβαση στις σχετικές εγγραφές τους (συγγραφείς, μεταφραστές), ο Explorer δεν δημιουργεί ένα ερώτημα για κάθε βιβλίο ξεχωριστά. Αντ' αυτού, εκτελεί μόνο ένα ερώτημα SELECT για κάθε τύπο σχέσης, μειώνοντας σημαντικά το φορτίο της βάσης δεδομένων. Για παράδειγμα:
Αυτός ο κώδικας θα εκτελέσει μόνο τρία βελτιστοποιημένα ερωτήματα στη βάση δεδομένων:
Η λογική για τον προσδιορισμό της συνδετικής στήλης καθορίζεται από την υλοποίηση των Συμβάσεων. Συνιστούμε τη χρήση του DiscoveredConventions, το οποίο αναλύει τα ξένα κλειδιά και σας επιτρέπει να εργάζεστε απρόσκοπτα με τις υπάρχουσες σχέσεις πινάκων.
Πρόσβαση στον πίνακα "παιδί
Η πρόσβαση στον πίνακα „παιδί“ λειτουργεί προς την αντίθετη
κατεύθυνση. Τώρα ρωτάμε ποια βιβλία έγραψε αυτός ο συγγραφέας ή
ποια βιβλία μετέφρασε αυτός ο μεταφραστής. Για αυτού του είδους το
ερώτημα, χρησιμοποιούμε τη μέθοδο related()
, η οποία επιστρέφει ένα
αντικείμενο Selection
με σχετικές εγγραφές. Ακολουθεί ένα
παράδειγμα:
Η μέθοδος related()
δέχεται την περιγραφή της σχέσης ως ενιαίο
όρισμα με τη χρήση σημείωσης τελείας ή ως δύο ξεχωριστά ορίσματα:
Ο Explorer μπορεί να εντοπίσει αυτόματα τη σωστή στήλη σύνδεσης με βάση
το όνομα του γονικού πίνακα. Σε αυτή την περίπτωση, συνδέει μέσω της
στήλης book.author_id
επειδή το όνομα του πίνακα προέλευσης είναι
author
:
Εάν υπάρχουν πολλαπλές πιθανές συνδέσεις, ο Explorer θα πετάξει μια εξαίρεση AmbiguousReferenceKeyException.
Μπορούμε, φυσικά, να χρησιμοποιήσουμε τη μέθοδο related()
και κατά
την επανάληψη πολλαπλών εγγραφών σε έναν βρόχο, και ο Explorer θα
βελτιστοποιήσει αυτόματα τα ερωτήματα και σε αυτή την περίπτωση:
Αυτός ο κώδικας παράγει μόνο δύο αποδοτικά ερωτήματα SQL:
Σχέση Πολλοί-προς-Πολλούς
Για μια σχέση πολλών προς πολλούς (Μ:Ν), απαιτείται ένας πίνακας
σύνδεσης (στην περίπτωσή μας, book_tag
). Ο πίνακας αυτός περιέχει
δύο στήλες ξένου κλειδιού (book_id
, tag_id
). Κάθε στήλη
αναφέρεται στο πρωτεύον κλειδί ενός από τους συνδεδεμένους πίνακες.
Για να ανακτήσουμε τα συνδεδεμένα δεδομένα, πρώτα αντλούμε εγγραφές
από τον πίνακα σύνδεσης χρησιμοποιώντας το related('book_tag')
, και στη
συνέχεια συνεχίζουμε με τα δεδομένα-στόχο:
Ο Explorer βελτιστοποιεί και πάλι τα ερωτήματα SQL σε μια αποδοτική μορφή:
Ερώτηση μέσω σχετικών πινάκων
Στις μεθόδους where()
, select()
, order()
και group()
,
μπορείτε να χρησιμοποιήσετε ειδικούς συμβολισμούς για να αποκτήσετε
πρόσβαση σε στήλες από άλλους πίνακες. Ο Explorer δημιουργεί αυτόματα τις
απαιτούμενες JOINs.
Ο συμβολισμός Dot (parent_table.column
) χρησιμοποιείται για σχέσεις
1:Ν, όπως φαίνεται από την οπτική γωνία του μητρικού πίνακα:
Ο συμβολισμός με τελεία χρησιμοποιείται για σχέσεις 1:Ν από την οπτική γωνία του γονικού πίνακα:
Στο παραπάνω παράδειγμα με συμβολισμό άνω και κάτω τελείας
(:book.title
), η στήλη ξένου κλειδιού δεν προσδιορίζεται ρητά. Η
Εξερεύνηση εντοπίζει αυτόματα τη σωστή στήλη με βάση το όνομα του
γονικού πίνακα. Σε αυτή την περίπτωση, συνδέεται μέσω της στήλης
book.author_id
επειδή το όνομα του πίνακα προέλευσης είναι author
.
Εάν υπάρχουν πολλαπλές πιθανές συνδέσεις, ο Explorer πετάει την εξαίρεση AmbiguousReferenceKeyException.
Η στήλη σύνδεσης μπορεί να καθοριστεί ρητά σε παρένθεση:
Οι συμβολισμοί μπορούν να συνδεθούν αλυσιδωτά για πρόσβαση σε δεδομένα σε πολλούς πίνακες:
Επέκταση των όρων για JOIN
Η μέθοδος joinWhere()
προσθέτει πρόσθετες συνθήκες στις συνδέσεις
πινάκων στην SQL μετά τη λέξη-κλειδί ON
.
Για παράδειγμα, ας πούμε ότι θέλουμε να βρούμε βιβλία που έχουν μεταφραστεί από έναν συγκεκριμένο μεταφραστή:
Στη συνθήκη joinWhere()
, μπορείτε να χρησιμοποιήσετε τις ίδιες
δομές όπως στη μέθοδο where()
– τελεστές, σημεία τοποθέτησης,
πίνακες τιμών ή εκφράσεις SQL.
Για πιο σύνθετα ερωτήματα με πολλαπλές JOINs, μπορούν να οριστούν ψευδώνυμα πινάκων:
Σημειώστε ότι ενώ η μέθοδος where()
προσθέτει συνθήκες στη ρήτρα
WHERE
, η μέθοδος joinWhere()
επεκτείνει τις συνθήκες στη ρήτρα
ON
κατά τη διάρκεια των ενώσεων πινάκων.