Files
yii/docs/guide/de/database.arr.txt
2011-01-16 14:55:27 +00:00

584 lines
22 KiB
Plaintext

Relationale ActiveRecords
=========================
Wie man mit ActiveRecord Tabellendaten ausliest, haben wir bereits gezeigt. In
diesem Abschnitt soll es darum gehen, wie man mit AR Abfragen über
mehrere verknüpfte Tabellen ausführt.
Will man mit relationalen AR arbeiten, sollten in der Datenbank
[Constraints](http://de.wikipedia.org/wiki/Constraint) (sinngem.:
Zwangsbedingungen) für Fremdschlüssel definiert sein, um die Konsistenz
und Integrität der Daten zu gewährleisten.
Für die Beispiele in diesem Abschnitt verwenden wir dieses einfache
Beziehungsmodell:
![ER-Diagramm](er.png)
> Info|Info: Je nach DBMS werden Fremdschlüssel-Constraints auf
> unterschiedliche Arten unterstützt. So verwendet z.B. SQLite
> vor Version 3.6.19 keine Constraints. Man kann sie aber trotzdem
> beim Erstellen einer Tabelle angeben.
Angeben von Beziehungen
-----------------------
Bevor man relationale Abfragen mit AR durchführen kann, müssen die Beziehungen
zwischen den beteiligten AR-Klassen definiert werden.
Diese AR-Beziehungen gleichen denen der entsprechenden Datenbanktabellen.
In der Datenbank können zwei Tabellen A und B auf drei Arten miteinander
verknüpft sein: eins-zu-viele (1:n, z.B. zwischen `tbl_user` und `tbl_post`),
eins-zu-eins (1:1, z.B. zwischen `tbl_user` und `tbl_profile`) und
viele-zu-viele (n:m, z.B. zwischen `tbl_category` und
`tbl_post`). In AR sind vier Typen möglich:
- `BELONGS_TO` (gehört): Wenn die Tabellen A und B 1:n-verknüpft sind, dann
gilt: B gehört A (z.B. `Post` gehört `User`).
- `HAS_MANY` (hat viele): Auf der anderen Seite gilt bei der selben
1:n-Verknüpfung zwischen A und B: A hat viele B (z.B. `User` hat viele `Post`).
- `HAS_ONE` (hat ein): Dies ist ein Spezialfall von `HAS_MANY`, wobei A höchstens ein
B hat (z.B. `User` hat höchstens ein `Profile`).
- `MANY_MANY` (viele viele): Dies entspricht der n:m-Beziehung in der
Datenbank. Eine Verbindungstabelle wird benötigt, um die n:m-Beziehung mit
zwei 1:n-Beziehungen abzubilden, da die meisten DBMS n:m-Beziehungen nicht
direkt unterstützen. In unserem Beispiel ist `tbl_post_category` eine solche
Tabelle. In AR-Terminologie kann man eine `MANY_MANY`-Beziehung als
Kombination einer `BELONGS_TO`- und einer `HAS_MANY`-Beziehung sehen. Beispielsweise gehört
`Post` zu vielen `Category` und `Category` hat viele `Post`.
Beziehungen werden in AR definiert, indem man die
[relations()|CActiveRecord::relations]-Methode von [CActiveRecord]
überschreibt. Sie liefert ein Array zurück, in dem jedes Element für eine
einzelne Beziehung steht:
~~~
[php]
'VarName'=>array('RelationsTyp', 'KlassenName', 'FremdSchlüssel', ...Zusätzliche Optionen)
~~~
`VarName` gibt den Namen, `RelationsTyp` die Art der Beziehung an. Sie wird
mit einer der vier Konstanten `self::BELONGS_TO`, `self::HAS_ONE`,
`self::HAS_MANY` und `self::MANY_MANY` festgelegt. `KlassenName` ist der Name
der AR-Klasse, zu der die Beziehung besteht. `FremdSchlüssel` gibt den/die zu
verwendenden Fremdschlüssel an. Schließlich können für jede Definition noch
weitere Optionen angegeben werden (worauf wir weiter unten noch genauer eingehen).
Hier ein Beispiel, wie die Beziehung zwischen `User` und `Post` angegeben
wird:
~~~
[php]
class Post extends CActiveRecord
{
public function relations()
{
return array(
'author'=>array(self::BELONGS_TO, 'User', 'author_id'),
'categories'=>array(self::MANY_MANY, 'Category',
'tbl_post_category(post_id, category_id)'),
);
}
}
class User extends CActiveRecord
{
......
public function relations()
{
return array(
'posts'=>array(self::HAS_MANY, 'Post', 'author_id'),
'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'),
);
}
}
~~~
> Info|Info: Es gibt auch zusammengesetzte Fremdschlüssel, die zwei oder
> mehr Spalten verwenden. In diesem Fall müssen alle Spaltennamen des
> Fremdschlüssels hintereinander mit Komma getrennt angegeben
> werden. Außerdem benötigt die MANY_MANY-Beziehung zusätzlich den Namen der
> Verknüpfungstabelle. Er wird zusammen mit dem Fremdschlüssel wie in diesem
> Beispiel für die `categories`-Beziehung in `Post` angegeben:
> `tbl_post_category(post_id, category_id)`.
Für jede dieser Beziehungsdefinitionen wird automatisch eine implizite
Eigenschaft in der AR-Klasse erzeugt, über die man auf die entsprechend
verknüpften AR-Objekte zugreifen kann, nachdem eine relationale Abfrage
durchgeführt wurde. Ist `$author` z.B. Instanz der AR-Klasse `User`,
stehen in `$author->posts` verknüpften `Post`-Instanzen zur Verfügung.
Ausführen von relationalen Abfragen
-----------------------------------
Am einfachsten führt man eine relationale Abfrage aus, indem man eine der
eben erwähnten relationalen Eigenschaften eines AR-Objekts ausliest. Falls
es sich um den ersten Zugriff handelt, wird automatisch eine weitere Abfrage
(gefiltert nach dem Primärschlüssel der AR-Instanz) auf die verknüpfte Tabelle
durchgeführt. Das Ergebnis wird dann in Form einer (oder mehrerer) AR-Instanz
(bzw. Instanzen) in der entsprechenden Eigenschaft gespeichert. Man spricht hier auch
von *lazy loading* (träges Nachladen), da die Abfrage erst bei Zugriff auf die
relationale Eigenschaft erfolgt. Hier ein Beispiel:
~~~
[php]
// Frage den Beitrag mit der ID 10 ab
$post=Post::model()->findByPk(10);
// Frage den Autor des Beitrags ab: Hier wird eine relationale Abfrage durchgeführt
$author=$post->author;
~~~
> Info|Info: Wurden keine verknüpften Einträge gefunden, so ist die
> entsprechende relationale Eigenschaft entweder `null` (für `BELONGS_TO`- und
> `HAS_ONE`-Beziehungen) oder ein leeres Array (für `HAS_MANY`- und
> `MANY_MANY`-Beziehungen). Beachten Sie bitte auch, dass Sie bei `HAS_MANY`- und
> `MANY_MANY`-Beziehungen die relationalen Eigenschaften in einer Schleife durchlaufen
> müssen, um auf die verknüpften AR-Objekte zugreifen zu können. Andernfalls
> erhalten Sie die typische "Trying to get property of
> non-object"-Fehlermeldung.
Mit der `lazy loading`-Methode lässt es sich bequem arbeiten. Allerdings ist
sie nicht immer sehr effizient. Wollte man zum Beispiel auf die
`author`-Information von `N` Posts zugreifen, müssten `N` relationale
Abfragen durchgeführt werden. Hier bietet sich daher stattdessen die
sogenannte *eager loading*-Methode (sinngem.: begieriges Laden) an.
Beim `Eager loading` werden die verknüpften AR-Instanzen gemeinsam mit dem
Hauptobjekt abgefragt. Dazu muss man einem [find|CActiveRecord::find]-
oder [findAll|CActiveRecord::findAll]-Aufruf lediglich einen
[with()|CActiveRecord::with]-Aufruf voranstellen:
~~~
[php]
$posts=Post::model()->with('author')->findAll();
~~~
Das Ergebnis ist ein Array von `Post`-Objekten, bei denen jeweils - anders als beim
`lazy loading` bereits vor dem ersten Zugriff - die `author`-Eigenschaft mit
der verknüpften `User`-Instanz befüllt wurde. Anstatt für jeden Post eine
weitere Abfrage durchzuführen, liefert der `eager loading`-Ansatz sämtliche
Beiträge zusammen mit ihren Autorne in einer einzigen JOIN-Abfrage zurück.
Die [with()|CActiveRecord::with]-Methode akzeptiert auch mehrere
Beziehungsnamen, die dann alle auf einmal abgefragt werden. Mit diesem Aufruf
erhält man zum Beispiel alle Beiträge inklusive ihrer Autoren und Kategorien:
~~~
[php]
$posts=Post::model()->with('author','categories')->findAll();
~~~
Man kann `eager loading` sogar verschachteln. Dazu werden die Beziehungsnamen
in hierarchischer Form an die [with()|CActiveRecord::with]-Methode übergeben:
~~~
[php]
$posts=Post::model()->with(
'author.profile',
'author.posts',
'categories')->findAll();
~~~
Dieses Beispiel liefert alle Beiträge zusammen mit ihrem Autor und den
Kategorien zurück. Zusätzlich wird zu jedem Autor auch gleich sein Profil
sowie die Liste aller seiner Beiträge abgefragt.
Seit Version 1.1.0 kann `eager loading` auch über die
[CDbCriteria::with]-Eigenschaft angestoßen werden:
~~~
[php]
$criteria=new CDbCriteria;
$criteria->with=array(
'author.profile',
'author.posts',
'categories',
);
$posts=Post::model()->findAll($criteria);
~~~
oder
~~~
[php]
$posts=Post::model()->findAll(array(
'with'=>array(
'author.profile',
'author.posts',
'categories',
)
);
~~~
Optionen für relationale Abfragen
---------------------------------
Wie erwähnt, können bei der Definition einer Beziehung weitere Optionen als
Name-Wert-Paare angeben werden, um die zugehörige relationale Abfrage
seinen Wünschen anzupassen. Diese Optionen stehen zur Verfügung:
- `select`: Liste der abzufragenden Spalten der verknüpften AR-Klasse.
Der Standardwert ist '*', d.h. alle Spalten. Spaltennamen sollten
vereindeutigt werden.
- `condition`: Die `WHERE` Klausel, standardmäßig leer. Spaltennamen
sollten vereindeutigt werden.
- `params`: Parameter (als Name-Wert-Paare), die an die erzeugte SQL Abfrage gebunden werden
sollen. Verfügbar seit Version 1.0.3.
- `on`: Zusätzliche `ON` Klausel, die an die JOIN-Kondition
mit einem `AND` Operator angehängt werden soll. Die Spaltennamen sollten
vereindeutigt werden. Bei `MANY_MANY`-Beziehungen wird diese Option ignoriert.
Sie ist seit Version 1.0.2 verfügbar.
- `order`: Die `ORDER BY` Klausel, standardmäßig leer. Spaltennamen
sollten vereindeutigt werden.
- `with`: Eine Liste von Relationen, die zusammen mit diesem Objekt
geladen werden sollen. Beachten Sie, dass bei falscher Verwendung dieser
Option eine Endlosschleife entstehen kann.
- `joinType`: Der Typ des JOINs für diese Beziehung. Der Standardwert ist `LEFT
OUTER JOIN`.
- `alias`: Der Alias für die verknüpfte Tabelle. Diese Option ist seit Version 1.0.1 verfügbar.
Mit dem Standardwert `null` wird der Beziehungsname als Alias verwendet.
- `together`: Ob ein JOIN der verknüpften Tabelle mit der Haupt- bzw. anderen Tabellen
erzwungen werden soll. Diese Option ist nur für `HAS_MANY` und `MANY_MANY` von Bedeutung.
Setzt man diesen Wert auf `false`, wird eine separate SQL-Abfrage für die verknüpfte Tabelle
ausgeführt, wodurch die ganze Abfrage in manchen Fällen beschleunigt wird, da
weniger gleiche Daten pro Zeile übertragen werden müssen. Ist die Option `true`
wird die verknüpfte Tabelle immer mittels JOIN zusammen mit der Haupttabelle
abgefragt, auch wenn diese seitenweise ausgelesen wird (Pagination).
Bleibt die Option leer, wird die verbundene Tabelle nur dann
zusammen mit der Haupttabelle in einer einzigen Abfrage eingelesen, falls
diese keine Seitenblätterung verwendet. Für weitere Informationen
lesen Sie bitte auch den Abschnitt "Geschwindigkeit von relationalen Abfragen".
Diese Option ist seit Version 1.0.3 verfügbar.
- `join`: Zusätzliche `JOIN`-Ausdrück, standardmäßig leer. Diese Option ist seit
Version 1.1.3 verfügbar.
- `group`: Die `GROUP BY` Klausel, standardmäßig leer. Spaltennamen
sollten vereindeutigt werden.
- `having`: Die `HAVING` Klausel, standarmäßig leer. Spaltennamen
sollten vereindeutigt werden. Diese Option ist seit Version 1.0.1. verfügbar.
- `index`: Der Spaltenname, deren Wert als Schlüssel für den Array mit
relationalen Objekten verwendet werden soll. Wird diese Option nicht gesetzt,
wird ein 0-basierter ganzzahliger Index verwendet.
Diese Option kann nur für `HAS_MANY`- und `MANY_MANY`-Beziehungen gesetzt
werden. Diese Option ist seit Version 1.0.7 verfügbar.
Zusätzlich sind beim `lazy loading` folgende Optionen für bestimmte Beziehungen
verfügbar:
- `limit`: Limit der abzufragenden Zeilen. Kann NICHT mit `BELONGS_TO`
verwendet werden.
- `offset`: Offset der abzufragenden Zeilen. Kann NICHT mit `BELONGS_TO`
verwendet werden.
Hier sehen Sie am Beispiel der `posts`-Beziehung in `User`, wie man einige dieser
Optionen verwenden kann:
~~~
[php]
class User extends CActiveRecord
{
public function relations()
{
return array(
'posts'=>array(self::HAS_MANY, 'Post', 'author_id',
'order'=>'posts.create_time DESC',
'with'=>'categories'),
'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'),
);
}
}
~~~
Greift man auf `$author->posts` zu, erhält man die `posts` des
`author` absteigend sortiert nach ihrer `creation time` (Erstellzeitpunkt).
Außerdem wurden die Kategorien zu jedem Post mit geladen.
Vereindeutigung von Spaltennamen
--------------------------------
Wenn ein Spaltenname in zwei oder mehr Tabellen auftaucht, die gemeinsam
abgefragt werden sollen, so muss dieser Name vereindeutigt werden. Dies
geschieht, indem man den Tabellenalias vor den Spaltennamen stellt.
Bei relationalen Abfragen hat die Haupttabelle den festen Alias `t`, während
alle relationalen Tabellen standardmäßig den Namen der
entsprechenden Beziehung verwenden. Im folgenden Beispiel stehen die
Aliase `t` und `comments` für die Tabellen `Post` und `Comment`:
~~~
[php]
$posts=Post::model()->with('comments')->findAll();
~~~
Nehmen wir nun an, dass es sowohl in `Post`, als auch in `Comment` eine
Spalte namens `create_time` gibt, die den Erstellzeitpunkt des jeweiligen
Eintrags enthält. Wenn man alle Beiträge zusammen mit ihren Kommentaren
abfragen möchten und die Ergebnisse nacheinander nach der Erstellzeit der Beiträge und
der der Kommentare sortieren will, muss `create_time` wie folgt vereindeutigt
werden:
~~~
[php]
$posts=Post::model()->with('comments')->findAll(array(
'order'=>'t.create_time, comments.create_time'
));
~~~
> Note|Hinweis: Die Art und Weise, wie Spaltennamen eindeutig angesprochen
> werden, hat sich seit Version 1.1.0 geändert. In früheren 1.0.x-Versionen hat
> Yii automatisch ein Alias für jede verknüpfte Tabelle erstellt und man
> musste die Präfix `??.` als Platzhalter für diesen Alias verwenden. Der
> Alias der Haupttabelle entsprach deren Namen.
Dynamische Optionen für relationale Abfragen
--------------------------------------------
Seit Version 1.0.2 kann man sowohl beim [with()|CActiveRecord::with]-Aufruf
als auch bei der `with`-Eigenschaft dynamische Optionen angeben. Diese
überschreiben dann jene Optionen, die fest in
[relations()|CActiveRecord::relations] definiert wurden. Möchte man zum
Beispiel beim obigen `User`-Model per `eager loading` gemeinsam alle Beiträge in
*aufsteigender Reihenfolge* abfragen, kann man die `order`-Option wie folgt
überschreiben:
~~~
[php]
User::model()->with(array(
'posts'=>array('order'=>'post.create_time ASC'),
'profile',
))->findAll();
~~~
Seit Version 1.0.5 kann man auch beim `lazy loading` dynamisch Optionen
überschreiben, indem man den Beziehungsnamen als Methode aufruft, und die
dynamischen Optionen als Parameter übergibt. Dieser Aufruf liefert zum
Beispiel alle Beiträge mit `status` 1 eines Benutzers:
~~~
[php]
$user=User::model()->findByPk(1);
$posts=$user->posts(array('condition'=>'status=1'));
~~~
Geschwindigkeit von relationalen Abfragen
-----------------------------------------
Wie erwähnt bietet sich der `eager loading`-Ansatz für Fälle an, in denen auf viele
verknüpfte Objekte zugegriffen werden muss. Er erzeugt einen langen komplizierten
SQL-Ausdruck in dem alle benötigten Tabellen mit JOIN eingebunden werden.
In vielen Fällen ist ein solcher langer SQL-Ausdruck vorzuziehen, da es damit
einfacher wird, nach Spalten in verbundenen Tabellen zu filtern. In einigen
Fällen kann das jedoch auch uneffizient werden.
Angenommen, man möchte die letzten Blogbeiträge zusammen mit den verknüpften Kommentaren
abfragen. Falls jeder Beitrag 10 Kommentare hat, enthielten viele Ergebniszeilen
redundante Daten. Mit jedem Beitragskommentar würden nämlich die selben
Beitragsdaten nochmal übermittelt werden. Ein anderer Ansatz wäre daher,
zunächst die letzten Blogbeiträge und danach erst die zugehörigen
Kommentare abzufragen. Dafür werden zwar zwei SQL-Abfragen benötigt, allerdings mit
dem Vorteil, keine redundanten Daten mehr übertragen zu müssen.
Welche Methode ist nun effizienter? Darauf gibt es keine endgültige Antwort.
Eine einzelne große SQL-Abfrage kann schneller sein, da die Datenbank weniger
zusätzliche Zeit für das Analysieren und Ausführen einzelner SQL-Abfragen benötigt.
Andererseits führt ein großer SQL-Ausdruck zu mehr redundanten Daten und
benötigt daher mehr Zeit diese zu übertragen und zu verarbeiten.
Um je nach Bedarf zwischen beiden Varianten wählen zu können, bietet Yii die
`together`-Option. Standardmäßig verfolgt Yii den ersten Ansatz, verwendet
also einen einzelnen SQL-Ausdruck bei `eager loading`. Setzt man `together`
bei der Definition einer Beziehungen auf `false`, werden die entsprechenden Tabellendaten
mit separaten Abfragen eingeholt. Will man also den zweiten Ansatz verwenden,
um die letzten Blogbeiträge mit ihren Kommentaren einzulesen, kann man die
Beziehung `comments` in `Post` so definieren:
~~~
[php]
public function relations()
{
return array(
'comments' => array(self::HAS_MANY, 'Comment', 'post_id', 'together'=>false),
);
}
~~~
Man kann diese Option auch dynamisch beim eager loading setzen:
~~~
[php]
$posts = Post::model()->with(array('comments'=>array('together'=>false)))->findAll();
~~~
> Note|Hinweis: In Version 1.0.x führt Yii bei `N` `HAS_MANY`- oder `MANY_MANY`-Beziehungen
> standardmäßig `N+1` SQL-Abfragen aus. Jede dieser Beziehungen führt also zu einer weiteren
> SQL-Abfrage. Um auch hier eine einzelne Abfrage zu erzwingen, kann man die `together()`-Methode
> nach `with()` aufrufen:
>
> ~~~
> [php]
> $posts=Post::model()->with(
> 'author.profile',
> 'author.posts',
> 'categories')->together()->findAll();
> ~~~
>
Statistische Abfragen
---------------------
> Note|Hinweis: Statistische Abfragen werden seit Version 1.0.4 unterstützt.
Neben den oben beschriebenen relationalen Abfragen unterstützt Yii auch sogenannte
statistische (auch: aggregierte) Abfragen. Damit können statistische
Informationen über verknüpfte Objekte abgefragt werden, wie
z.B. die Anzahl von Kommentaren zu einem Beitrag, die durchschnittliche
Bewertung eines Produkts, etc. Statistische Abfragen können nur mit
`HAS_MANY`- (z.B. ein Beitrag hat viele Kommentare) oder einer
`MANY_MANY`-Beziehungen (z.B. ein Beitrag gehört zu
vielen Kategorien und eine Kategorie hat viele Beiträge) verwendet werden.
Statistische Abfragen werden ähnlich wie relationale Abfrage durchgeführt und
müssen analog zunächst in [relations()|CActiveRecord::relations] definiert werden:
~~~
[php]
class Post extends CActiveRecord
{
public function relations()
{
return array(
'commentCount'=>array(self::STAT, 'Comment', 'post_id'),
'categoryCount'=>array(self::STAT, 'Category', 'post_category(post_id, category_id)'),
);
}
}
~~~
Damit werden zwei statistische Abfragen angegeben: `commentCount` errechnet die
Anzahl der Kommentare zu einem Beitrag und `categoryCount` die Anzahl von
Kategorien, denen ein Beitrag zugeordnet wurde. Beachten Sie, dass `Post` und
`Comment` in einer `HAS_MANY`-Beziehung zueineander stehen, während `Post` und
`Category` über eine `MANY_MANY`-Beziehung (über die Tabelle `post_category`)
verknüpft sind.
So deklariert kann man über `$post->commentCount` die Anzahl der Kommentare
eines Beitrags auslesen. Beim ersten Zugriff auf diese Eigenschaft wird
dazu implizit eine SQL-Abfrage durchgeführt. Dies entspricht wieder dem
bereits bekannten *lazy loading*-Ansatz. Soll die Anzahl der Kommentare für
mehrere Beiträge bestimmt werden, kann man stattdessen auch die
*eager loading*-Methode verwenden:
~~~
[php]
$posts=Post::model()->with('commentCount', 'categoryCount')->findAll();
~~~
Dieser Befehl führt drei SQL-Anweisungen aus um alle Beiträge zusammen mit der Anzahl
ihrer Kommentare und Kategorien zurückzuliefern. Würden man den *lazy
loading*-Ansatz verwenden, würde das bei `N` Beiträgen in `2*N+1` SQL-Abfragen resultieren.
Standardmäßig wird bei einer statistische Abfrage ein `COUNT`-Ausdruck
berechnet (und damit in obigem Beispiel die Anzahl der Kommentare und
Kategorien). Man kann auch dies über zusätzliche Beziehungsoptionen in
[relations()|CActiveRecord::relations] anpassen. Diese Optionen stehen zur
Verfügung:
- `select`: Der statistische Ausdruck. Vorgabewert ist `COUNT(*)`, was der
Anzahl der Kindobjekte entspricht.
- `defaultValue`: Standardwert für Zeilen, deren statistische Abfrage
"leer" ist. Hat ein Beitrag z.B. keine Kommentare, würde sein `commentCount`
diesen Wert erhalten. Vorgabewert ist 0.
- `condition`: Die `WHERE`-Bedingung. Standardmäßig leer.
- `params`: Die Parameter, die an die erzeugte SQL-Anweisung gebunden
werden sollen. Sie müssen als Array aus Name-Wert-Paare angegeben werden.
- `order`: Die `ORDER BY`-Anweisung. Standardmäßig leer.
- `group`: Die `GROUP BY`-Anweisung. Standardmäßig leer.
- `having`: Die `HAVING`-Anweisung. Standarmäßig leer.
Relationale Abfragen mit Scopes
-------------------------------
> Note|Hinweis: Scopes werden seit Version 1.0.5 unterstützt.
Auch relationale Abfragen können mit [Scopes](/doc/guide/database.ar#named-scopes)
kombiniert werden. Dabei unterscheidet man zwei Fälle: Scopes die auf das Hauptobjekt
und Scopes die auf die verknüpften Objekte angewendet werden.
Der folgende Code zeigt, wie Scopes mit dem Hauptobjekt verwendet werden:
~~~
[php]
$posts=Post::model()->veroeffentlicht()->kuerzlich()->with('comments')->findAll();
~~~
Dies unterscheidet sich kaum vom Vorgehen bei nicht-relationalen Abfragen. Der einzige
Unterschied besteht im zusätzlichen Aufruf von `with()` nach der Kette von
Scopes. Diese Abfrage würde also die kürzlich veröffentlichten
Beiträge zusammen mit ihren Kommentaren zurückliefern.
Bei verknüpften Objekten können Scopes so verwendet werden:
~~~
[php]
$posts=Post::model()->with('comments:kuerzlich:freigegeben')->findAll();
~~~
Diese Abfrage liefert alle Beiträge zusammen mit ihren freigegebenen
Kommentaren zurück. Beachten Sie, dass `comments` sich auf den Namen der
Beziehung bezieht, während `kuerzlich` und `freigegeben` zwei Scopes
sind, die in der Modelklasse `Comment` deklariert sind. Beziehungsname und
Scopes sollten durch Doppelpunkte getrennt werden.
Scopes können auch in den `with`-Optionen in [CActiveRecord::relations()]
angegeben werden. So würde man im folgenden Beispiel bei Zugriff auf
`$user->posts`, alle *freigegebenen* Kommentare eines Beitrags erhalten.
~~~
[php]
class User extends CActiveRecord
{
public function relations()
{
return array(
'posts'=>array(self::HAS_MANY, 'Post', 'author_id',
'with'=>'comments:freigegeben'),
);
}
}
~~~
> Note|Hinweis: Bei relationalen Abfragen können nur Scopes
verwendet werden, die in [CActiveRecord::scopes] definiert wurden. Man kann
daher keine parametrisierten Scopes verwenden.
<div class="revision">$Id: database.arr.txt 2782 2010-12-28 16:18:06Z qiang.xue $</div>