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

571 lines
25 KiB
Plaintext

Relacyjny Rekord Aktywny
========================
Dotychczas zobaczyliśmy jak używać Rekordu Aktywnego (AR) aby wybierać dane z jednej
tabeli bazodanowej. W tej sekcji opiszemy jak używać AR aby złączyć kilka powiązanych
tabel baz danych i zwrócić połączony zbiór danych.
W celu używania relacyjnego AR, wymagane jest, aby relacja dla obcego klucza głównego
była dobrze zdefiniowana pomiędzy tabelami, które będą łączone. AR bazuje na metadanych
tych relacji gdy decyduje jak połączyć tabele.
> Note|Uwaga: Poczynając od wersji 1.0.1, możesz używać relacyjnego AR nawet jeśli
> nie zdefiniowałeś kluczy obcych w swojej bazie danych.
Dla uproszczenia, będziemy używali schematu bazy danych pokazanego na następnym
diagramie zależności encji (ER) celem zilustrowania przykładów w tej sekcji.
![Diagram ER](er.png)
> Info|Info: Wsparcie dla ograniczeń kluczy obcych różni sie w różnych DBMS.
>
> SQLite < 3.6.19 nie wspiera ograniczeń kluczy obcych, lecz wciąż możesz deklarować
> ograniczenia, podczas tworzenia tabel. AR może wykorzystać te deklaracje
> aby prawidłowo wspierać relacyjne zapytania.
>
> MySQL wspiera ograniczenia kluczy obcych gdy używany jest silnik InnoDB,
> w przeciwieństwie do silnika MyISAM. Zalecamy zatem używanie InnoDB dla twoich
> baz danych MySQL.
> Podczas używania MyISAM, możesz wykorzystać następujący trik
> aby móc wykonywać relacyjne zapytania przy użyciu AR:
> ~~~
> [sql]
> CREATE TABLE Foo
> (
> id INTEGER NOT NULL PRIMARY KEY
> );
> CREATE TABLE bar
> (
> id INTEGER NOT NULL PRIMARY KEY,
> fooID INTEGER
> COMMENT 'CONSTRAINT FOREIGN KEY (fooID) REFERENCES Foo(id)'
> );
> ~~~
> Powyżej użyliśmy słowa kluczowego `COMMENT` aby opisać ograniczenia klucza obcego
> co może zostać przeczytanie przez AR aby rozponać opisywaną relację.
Deklarowanie relacji
----------------------
Zanim użyjemy AR aby wykonać relacyjne zapytanie, musimy powiedzieć AR jak
jedna klasa AR jest powiązana z drugą.
Relacja pomiędzy dwoma klasami AR jest bezpośrednio związana z relacją pomiędzy
tabelami bazy danych reprezentowanych przez klasę AR. Z punkty widzenia bazy danych
relacja pomiędzy dwoma tabelami A i B może występować w 3 wariantach:
jeden-do-wielu (ang. one-to-many; np. `tbl_user` i `tbl_post`), jeden-do-jednego (ang. one-to-one;
np. `tbl_user` i `tbl_profile`) oraz wiele-do-wielu (ang. many-to-many; np. `tbl_category` i `tbl_post`).
W AR występują cztery rodzaje relacji:
- `BELONGS_TO` (należy do): jeśli relacja pomiędzy tabelą A i B to jeden-do-jednego,
wtedy B należy do A (np. post `tbl_post` należy do użytkownika `tbl_user`);
- `HAS_MANY` (posiada wiele): jeśli relacja pomiędzy tabelą A i B to jeden-do-wielu
wtedy A ma wiele B (np. użytkownik `tbl_user` ma wiele postów `tbl_post`);
- `HAS_ONE` (posiada jedną): to jest specjalny przypadek relacji `HAS_MANY` gdzie A posiada
co najwyżej jedno B (np. użytkownik `tbl_user` ma co najwyżej jeden profil `tbl_profile`);
- `MANY_MANY` (wiele do wielu): odpowiada relacji bazodanowej wiele-do-wielu.
Aby rozbić relację wiele-do-wielu na jeden-do-wielu potrzebna jest tablica asocjacyjna,
gdyż wiele DBMS nie wspiera bezpośrednio relacji wiele-do-wielu.
W naszym przykładzie schemat bazy danych `tbl_post_category` zostanie użyty w tym celu.
W terminologii AR, możemy wytłumaczyć. W terminologii AR, możemy wytłumaczyć relację
wiele-do-wielu jako kombinację `BELONGS_TO` oraz `HAS_MANY`. Na przykład,
post `tbl_post` należy do wielu kategorii `tbl_category` a kategoria `tbl_category` posiada wiele postów `tbl_post`.
Deklarowanie relacji w AR wymaga nadpisania metody [relations()|CActiveRecord::relations]
z [CActiveRecord]. Metoda zwraca tablicę konfiguracji relacji. Każdy element tablicy
reprezentuje pojedynczą relację zapisaną w następującym formacie:
~~~
[php]
'NazwaZmiennej'=>array('TypRelacji', 'NazwaKlasy', 'KluczObcy', ...dodatkowe opcje)
~~~
gdzie `NazwaZmiennej` jest nazwą relacji; `TypRelacji` specyfikuje typ relacji i posiada
jedną z czterech stałych wartości:
`self::BELONGS_TO`, `self::HAS_ONE`, `self::HAS_MANY` oraz
`self::MANY_MANY`; `NazwaKlasy` jest nazwą klasy AR powiązanej z tą klasą; oraz
`KluczObcy` określa klucz(e) obcy(e) powiązane z tą relacją. Dodatkowe opcje moga być
określone na końcu każdej relacji (więcej szczegółów w dalszej części).
Następujący kod pokazuje jak możemy zadeklarować relację dla klasy użytkownika `User`
oraz postu `Post`.
~~~
[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: Klucz obcy może być kluczem złożonym, zawierającym dwie lub więcej kolumn.
W takim przypadku, powinniśmy złączyć nazwy kolumn dla kluczy obcych rozdzielając przecinkiem.
Dla typu relacji `MANY_MANY`, nazwa tablicy asocjacyjnej musi
również być określona w kluczu obcym. Na przykład, relacja kategorii `categories` w `tbl_post`
jest określona przez klucz obcy `tbl_post_category(post_id, category_id)`.
Deklaracja relacji w klasie AR domyślnie dodaje właściwość do klasy
dla każdej relacji. Po tym jak zapytanie relacyjne jest wykonywane, odpowiadająca
właściwość będzie wypełniona odpowiadającymi instancjami AR. Na przykład, jeśli `$author`
reprezentuje instancję AR `User`, możemy użyć `$author->posts` aby dostać się do
powiązanych instancji `Post`.
Wykonywanie zapytań relacyjnych
---------------------------
Najprostszym sposobem wykonania relacyjnego zapytania jest odczytanie relacyjnej
właściwości instancji AR. Jeśli właściwość nie była wcześniej odczytywana,
relacyjne zapytanie zostanie zainicjalizowane za pomocą którego złączymy dwie połączone z sobą
tabele i odfiltrujemy dane przy użyciu klucza głównego aktualnej instancji AR. Wynik zapytania
będzie zapisany we właściwości jako instancja(e) powiązanej klasy AR. Jest to znane
jako technika *opóźnionego ładowania* (ang. *lazy loading* approach), np. zapytanie
relacyjne jest wykonywane tylko wtedy, gdy powiązane obiekty są odczytywane są po
raz pierwszy. Poniższy przykład pokazuje jak używać tej techniki:
~~~
[php]
// zwróć post, którego ID wynosi 10
$post=Post::model()->findByPk(10);
// zwróć autora posta: tutaj będzie wykonane zapytanie relacyjne
$author=$post->author;
~~~
> Info|Info: Jeśli nie istnieją żadne powiązane instancje dla relacji,
odpowiednie właściwości mogą być pustą tablicą bądź wartością null.
Dla relacji `BELONGS_TO` oraz `HAS_ONE` wynikiem jest wartość null; dla
`HAS_MANY` oraz `MANY_MANY` jest to pusta tablica.
Zauważ, że relacje `HAS_MANY` oraz `MANY_MANY` zwracają tablicę obiektów, dlatego
będziesz musiał przejść w pętli przez zwrócony wynik, jeśli będziesz chciał uzyskać dostęp
do jakiejkolwiek właściwości obiektu. W przeciwnym przypadku, możesz uzyskać błąd: "Próbujesz
skorzystać z właściwości elementu nie będącego obiektem" (ang. "Trying to get property of non-object" errors).
Technika opóźnionego ładowania jest bardzo poręczne w użyciu, ale nie zawsze jest wydajne
we wszystkich scenariuszach. Dla przykładu, jeśli chcemy uzyskać dostęp do informacje o autorze dla
`N` postów, używając techniki opóźnionego ładowania wykonamy `N` zapytań z użyciem join.
W tych warunkach powinniśmy uciec się do tak zwanej techniki *zachłannego ładowania*
(ang. eager loading approach).
Technika zachłannego ładowania zwraca powiązane instancje AR razem z główną(ymi) instancją(ami) AR.
Osiągamy to poprzez użycie metody [with()|CActiveRecord::with] razem z jedną z metod AR
[find|CActiveRecord::find] lub [findAll|CActiveRecord::findAll]. Na przykład,
~~~
[php]
$posts=Post::model()->with('author')->findAll();
~~~
Powyższy kod zwróci tablicę instancji `Post`. W odróżnieniu od techniki leniwego ładowania
właściwość `author` w każdej instancji `Post` jest już wypełniona odpowiednią instancją
`User` przed jej pierwszym odczytaniem. Zamiast wywoływania zapytania z join dla
każdego posty, technika zachłannego ładowania zwraca wszystkie posty razem wraz z autorami
za pomocą jednego zapytania z join!
Możemy używać jednocześnie wielu nazw relacji w metodzie [with()|CActiveRecord::with]
a technika zachłannego łączenia dostarczy nam je z powrotem za jednym razem.
Na przykład, następujący kod zwróci posty razem z ich autorami oraz kategoriami:
~~~
[php]
$posts=Post::model()->with('author','categories')->findAll();
~~~
Możemy również korzystać z zagnieżdżonych zachłannych ładowań. Zamiast listy nazw relacji,
przekazujemy w postaci hierarchicznej nazwy relacji do metody [with()|CActiveRecord::with]
w następujący sposób:
~~~
[php]
$posts=Post::model()->with(
'author.profile',
'author.posts',
'categories')->findAll();
~~~
Powyższy przykład zwróci wszystkie posty razem z ich autorami oraz kategoriami.
Zwróci również dla każdego autora profil oraz posty.
Poczynając od wersji 1.1.0, zachłanne ładowanie może zostać również wywołane poprzez
określenie właściwości [CDbCriteria::with] w następujący sposób:
~~~
[php]
$criteria=new CDbCriteria;
$criteria->with=array(
'author.profile',
'author.posts',
'categories',
);
$posts=Post::model()->findAll($criteria);
~~~
lub
~~~
[php]
$posts=Post::model()->findAll(array(
'with'=>array(
'author.profile',
'author.posts',
'categories',
)
);
~~~
Opcje zapytań relacyjnych
------------------------
Wspominaliśmy, że dodatkowe opcje mogą być dookreślone w deklaracji relacji.
Opcje te zapisane jako pary nazw i wartości używane są w celu dostosowania do własnych
potrzeb zapytań relacyjnych. Poniżej znajdziemy ich zestawienie.
- `select`: lista kolumn, które będą zwrócone dla powiązanej klasy AR.
Domyślną wartością jest '*', oznaczająca wszystkie kolumny. Nazwy kolumn
do których się odwołujemy w tej opcji powinny zostać ujednoznacznione.
- `condition`: klauzula `WHERE`. Domyślnie pusta. Nazwy kolumn
do których się odwołujemy w tej opcji powinny zostać ujednoznacznione.
- `params`: parametry, które zostaną przypięte do wygenerowanego wyrażenia SQL.
Powinny zostać przekazane jako tablica par nazwa-wartość. Opcja ta jest dostępna
od wersji 1.0.3.
- `on`: klauzula `ON`. Warunki określone tutaj będą dołączone do warunków złączenia
przy użyciu operatora `AND`. Nazwy kolumn do których się odwołujemy w tej opcji
powinny zostać ujednoznacznione. Opcja ta jest dostępna od wersji 1.0.2.
- `order`: klauzula `ORDER BY`. Nazwy kolumn do których się odwołujemy
w tej opcji powinny zostać ujednoznacznione
- `with`: lista obiektów potomnych, które powinny zostać załadowane wraz z tym
obiektem. Należy pamiętać, że niewłaściwe użycie tej opcji może skutkować utworzeniem
nigdy niekończącej się pętli.
- `joinType`: typ złączenia dla relacji. Domyślna wartość to `LEFT OUTER JOIN`.
- `alias`: alias dla tablicy powiązanej z relacją. Opcja ta jest dostępna
od wersji 1.0.1. Domyślnie posiada wartość null, co oznacza iż alias tablicy
jest taki sam jak nazwa relacji.
- `together`: używana jeśli tabele powiązane mają zostać zmuszone do połączenia się razem
z główną tabelą. Opcja ta ma znaczenie dla relacji `HAS_MANY` oraz `MANY_MANY`.
Jeśli opcja ta ma wartość ustawioną jako false, wtedy tabela związana z relacją `HAS_MANY`
lub `MANY_MANY` zostanie połączona z tabelą główną w osobnym zapytaniu SQL, co może zwiększyć
ogólną wydajność zapytania, gdyż zwracana jest mniejsza ilość powtarzających się danych.
Jeśli ta opcja posiada wartość true, powiązana tabela będzie zawsze dołączona
do pierwszej tabeli za pomocą pojedyńczego zapytania SQL, nawet jeśli pierwsza tabela
jest stronicowana. Jeśli ta opcja nie jest ustawiona, powiązana tabela będzie dołączona
do pierwszej tabeli za pomocą pojedyńczego zapytania SQL tylko wtedy kiedy pierwsza tabela
nie jest stronicowana. Aby uzyskać więcej szczegółow, zobacz do działu "Wydajność zapytań relacyjnych".
- `join`: dodatkowa klauzula `JOIN`. Domyślnie pusta. Opcja ta jest dostępna od wersji 1.1.3.
- `group`: klauzula `GROUP BY`. Domyślnie pusta. Nazwy kolumn
do których się odwołujemy w tej opcji powinny zostać ujednoznacznione.
- `having`: klauzula `HAVING`. Domyślnie pusta. Nazwy kolumn
do których się odwołujemy w tej opcji powinny zostać ujednoznacznione.
Uwaga, opcja ta jest dostępna od wersji 1.0.1.
- `index`: nazwa kolumny, której wartość powinna zostać użyta jako klucz tablicy, która zawiera powiązane obiekty.
Bez ustawienia tej opcji, tablica obiektów powiązanych będzie używała indeksu całkowitoliczbowego rozpoczynającego się od liczby zero.
Opcja ta może zotać ustawiona tylko dla relacji `HAS_MANY` oraz `MANY_MANY`. Opcja ta jest dostępna od wesji 1.0.7.
Dodatkowo, następujące opcje są dostępne dla wybranych relacji podczas opóźnionego
ładowania:
- `limit`: ogranicza ilość zwracanych wierszy. Opcja ta nie ma zastosowania
dla relacji `BELONGS_TO`.
- `offset`: offset dla zwracanych wierszy. Opcja ta nie ma zastosowania
dla relacji `BELONGS_TO`.
Poniżej zmodyfikujemy deklarację relacji `posts` w klasie `User` poprzez
wybranie części z powyższych opcji.
~~~
[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'),
);
}
}
~~~
Teraz jeśli odczytamy `$author->posts`, powinniśmy otrzymać autorów postów
posortowanych malejąco wg czasu ich utworzenia. Każda instancja postu będzie
również posiadała wczytaną odpowiadającą jej kategorię.
Ujednoznacznianie nazw kolumn
---------------------------
Kiedy nazwa kolumny pojawia się w dwóch lub więcej tabelach, które będą łączone
należy ją ujednoznacznić (rozróżnić). Robi się to poprzedzając nazwę kolumny
prefiksem będącym aliasem nazwy tabeli.
Domyślnie, w relacyjnych zapytaniach AR alias nazwy dla głównej tabeli ustalony jest
jako `t`, gdy zaś alias nazwy dla tabeli relacyjnej jest taki sam jak odpowiadająca
Na przykład, w kolejnym wyrażeniu aliasem nazwy dla postu `Post` oraz komentarza `Comment`
są odpowiednio `t` oraz `comments`:
~~~
[php]
$posts=Post::model()->with('comments')->findAll();
~~~
Załóżmy teraz, że zarówno `Post` oraz `Comment` posiadają kolumnę czas utworzenia `create_time`
postu lub komentarza i chcemy pobrać posty razem z ich komentarzami, najpierw sortując po czasie
utworzenia postów a następnie po czasie utworzenia komentarzy. Potrzebujemy ujednoznacznić
kolumnę czasu utworzenia `create_time` w następujący sposób:
~~~
[php]
$posts=Post::model()->with('comments')->findAll(array(
'order'=>'t.create_time, comments.create_time'
));
~~~
> Note|Uwaga: sposób ujednoznaczniania kolumn zmienił się od wersji 1.1.0.
> Poprzednie w wersji 1.0.x, Yii domyślnie generowało w sposób automatyczny
> alias tabeli sla każdej tabeli relacyjnej i musieliśmy używać prefiksu `??.`
> w celu odniesienia się do automatycznie wygenerowanego aliasu. Również, w wersji
> 1.0.x, alias nazwy tabeli głównej był nazwą samej tabeli.
Dynamiczne opcje pytań relacyjnych
--------------------------------
Wraz z wersją 1.0.2 możemy używać dynamicznych opcji zapytań relacyjnych zarówno w metodzie
[with()|CActiveRecord::with] jak i opcji `with`. Dynamiczne opcje nadpiszą istniejące
opcje tak jak zostało to określone w metodzie [relations()|CActiveRecord::relations].
Na przykład, dla powyższego modelu `User`, jeśli chcemy używać techniki zachłannego ładowania
aby zwrócić posty należące do autora sortujące jest rosnąco
(opcja `order` w specyfikacji relacji jest malejąca), możemy zrobić to następująco:
~~~
[php]
User::model()->with(array(
'posts'=>array('order'=>'posts.create_time ASC'),
'profile',
))->findAll();
~~~
Poczynając od wersji 1.0.5, opcje dynamicznych zapytań mogą być również używane dla leniwego ładowania
w celu wykonywania zapytań relacyjnych. Aby to zrobić, powinniśmy wywołać metodę, której nazwa jest identyczna
z nazwą relacji oraz przekazać opcje dynamicznego zapytania jako parametr metody.
Na przykład, następujący kod zwróci posty użytkownika, których `status` wynosi 1:
~~~
[php]
$user=User::model()->findByPk(1);
$posts=$user->posts(array('condition'=>'status=1'));
~~~
Wydajność relacyjneych zapytań
----------------------------
Jak opisaliśmy powyżej, zachłanne ładowanie jest używant w scenariuszu, gdy potrzebujemy otrzymać
dostęp do wielu powiązanych obiektów. Generuje one duże, złożone zapytanie SQL
poprzed połączenie wszystkich potrzebnych tabel. Duże zapytanie SQL
jest prefereoane w wielu przypadkach, ponieważ upraszcza filtrowanie
oparte na kolumnie w relacyjnych tabelach. Jednakże może ono być
nieefektowne w niektórych przypadkach.
Rozważmy przypadek, gdzie potrzebujemy znaleźć ostatnie posrt raze z ich komentarzami.
Zakładając, że każdy post posiada 10 kometarzy, używanie pojedynczego, dużego zapytania SQL,
zwróci wiele powtarzającycj się danych postów, ze względu na to, że każdy post będzie powtórzony
dla każdego posiadanego komentarza.
Z nowym podejściem potrzebujemy wywołać dwa zapytanie SQL. Korzyścią z tego płynącą jest brak
redundancji w zwróconych rezultach zapytania.
Zatem, które podejście jest bardziej wydajne? Nie ma jednoznacznej odpowiedzi.
Wywołanie pojedynczego, dużego zapytania SQL może być bardziej wydajne ponieważ
powoduje mniejsze obciążenie DBMS podczas parsowania i wykonywania zapytania SQL.
Z drugiej strony używajać pojedynczego zapytania SQL, mamy w końcu więcej redundantnych
dancyh i w ten sposób potrzebujemy więcej czasu by je odczytać i przetworzyć.
Z tego powodu Yii dostarcza opcję zapytania `together`, tak by można było wybierać pomiędzy
oboma podejściami w zależności od potrzeb. Domyślnie przyjmuje pierwsze podejście, czyli
tworzy jedno zapytanie SQL aby wykonać zachłanne ładowanie. Możemy ustawić opcję `together`
jako false w deklaracji zapytania, tak że część tabel będzie połączona w oddzielnym zapytaniu SQL.
Na przykład odpytując o ostanie posty wraz z ich komentarzami, w celu użycia drugiego podejścia,
możemy zadeklarować relację `comments` w klasie `Post` następująco:
~~~
[php]
public function relations()
{
return array(
'comments' => array(self::HAS_MANY, 'Comment', 'post_id', 'together'=>false),
);
}
~~~
Możemy również dynamicznie ustawić tą opcję kiedy wykonujemy zachłanne ładowanie:
~~~
[php]
$posts = Post::model()->with(array('comments'=>array('together'=>false)))->findAll();
~~~
> Note|Uwaga: W wersji 1.0.x, domyślnym zachowaniem Yii jest generowanie i wykonywanie
> `N+1` zapytań SQL, jeśli występuje `N` relacji `HAS_MANY` lub `MANY_MANY`.
> Każda relacja `HAS_MANY` lub `MANY_MANY` posiada swoje własne zapytanie SQL. Poprzez wywołanie
> metody `together()` po `with()`, możemy narzucić wygenerowania i wykonanie się tylko
> jednego zapytania SQL. Na przykład:
>
> ~~~
> [php]
> $posts=Post::model()->with(
> 'author.profile',
> 'author.posts',
> 'categories')->together()->findAll();
> ~~~
Zapytania statystyczne (ang. Statistical Query)
-----------------
> Note|Uwaga: Zapytania statystyczne są wspierane od wersji 1.0.4
Poza zapytaniami relacyjnymi opisanymi powyżej, Yii wspiera również tak zwane zapytania statystyczne (lub zapytania agregacyjne). Odnoszą się one do uzyskiwania agregowanych
informacji o powiązanych obiektach, takich jak liczba komentarzy dla każdego postu, średni ocena dla każdego produktu, itp. Zapytania statystyczne mogą być wykonywane dla obiektów
wskazywanych w relacji `HAS_MANY` (np. post ma wiele komentarzy) lub `MANY_MANY` (np. post należy do wielu kategorii a kategoria ma wiele postów).
Wykonywania zapytań statystycznych jest bardzo podobne do wykonywania opisanych wcześniej zapytań relacyjnych. Najpierw musimy zdefiniować zapytanie statystyczne w metodzie
[relations()|CActiveRecord::relations] klasy [CActiveRecord] tak jak robimy to dla zapytań relacyjnych.
~~~
[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)'),
);
}
}
~~~
Powyżej zadeklarowaliśmy dwa zapytania statystyczne: `commentCount` oblicza ilość komentarzy należących do postu a `categoryCount` oblicza ilość kategorii do których należy post.
Zauważ, że relacja pomiędzy `Post` a `Comment` jest relacją `HAS_MANY`, podczas gdy relacja pomiędzy `Post` a `Category` jest relacją `MANY_MANY`
(wraz z łączącą je tabelą `post_category`). Jak możemy zauważyć, deklaracja jest bardzo podobna do tych z relacji opisywanych we wcześniejszych podpunktach.
Jedyną różnicą jest to, że typem relacji jest tutaj `STAT`.
Przy użyciu powyższej deklaracji możemy otrzymać ilość komentarzy dla postu przy użyciu wyrażenia `$post->commentCount`. Jeśli użyjemy tej właściwości po raz pierwszy,
wyrażenie SQL zostanie wywołane w ukryciu w celu uzyskania pożądanego rezultatu. Jak już wiemy, jest to tak zwane *leniwe ładowanie*.
Możemy również używać *zachłannego ładowania* jeśli chcemy dowiedzieć uzyskać ilość komentarzy dla wielu postów.
~~~
[php]
$posts=Post::model()->with('commentCount', 'categoryCount')->findAll();
~~~
Powyższe wyrażenie wykona trzy zapytania SQL aby zwrócić wszystkie posty razem z policzonymi komentarzami oraz policzonymi kategoriami. Używając podejścia leniwego ładowania
skończylibyśmy z `2*N+1` zapytaniami SQL, gdzie `N` to ilość postów.
Domyślnie zapytanie statystyczne użyje wyrażenia `COUNT` do obliczeń (i w ten sposób policzymy komentarze oraz kategorie w powyższych przykładach). Możemy je dostosować
do własnych potrzeb poprzez określenie dodatkowych opcji podczas deklarowania go w metodzie [relations()|CActiveRecord::relations]. Podsumowanie dostępnych opcji znajduje się poniżej.
- `select`: wyrażenie statystyczne. Domyślnie `COUNT(*)`, co oznacza liczenie obiektów potomnych.
- `defaultValue`: wartość jaka będzie przypisana do tych rekordów, dla których nie zostaną zwrócone rezultaty zapytania statystycznego. Na przykład, jeśli post nie posiada
żadnych komentarzy, jego `commentCount` otrzyma tą wartość. Wartość domyślna dla tej opcji to zero.
- `condition`: klauzula `WHERE`. Domyślnie jest pusta.
- `params`: parametry, które mają zostać związane z wygenerowanym zapytaniem SQL. Powinny być one przekazane jako tablica par nazwa-wartość.
- `order`: klauzula `ORDER BY`. Domyślnie jest pusta.
- `group`: klauzula `GROUP BY`. Domyślnie jest pusta.
- `having`: klauzula `HAVING`. Domyślnie jest pusta.
Relacyjne zapytania z nazwanymi podzbiorami
----------------------------------
> Note|Uwaga: Wsparcie dla nazwanych podzbiorów zostało wprowadzone wraz z wersją 1.0.5.
Relacyjne zapytania mogą być wykonywane w połączeniu z [nazwanymi zbiorami](/doc/guide/database.ar#named-scopes).
Rozróżniamy dwa przypadki. W pierwszym, nazwany podzbiór stosowany jest do głównego modelu. W drugim, nazwany podzbiór stosowany jest
do powiązanego modelu.
Następujący kod pokazuje, jak zastosować nazwane podzbiory do głównego modelu.
~~~
[php]
$posts=Post::model()->published()->recently()->with('comments')->findAll();
~~~
Przypomina to bardziej nierelacyjne zapytania. Jedyna różnica polega na tym, że mamy wywołanie metody `with()`
po łańcuchu wywołań nazwanych podzbiorów. Zapytanie zwróci ostatnio opublikowane posty wraz z ich komentarzami.
Następujący kod pokazuje, jak zastosować nazwane podzbiory do modelu powiązanego.
~~~
[php]
$posts=Post::model()->with('comments:recently:approved')->findAll();
~~~
Powyższe zapytanie zwróci wszystkie posty wraz z zatwierdzonymi komentarzami. Zauważ, że `comments` jest referencją
do nazwy relacji, a `recently` oraz `approved` referuje do dwóch nazwanych podzbiorów w klasie modelu `Comment`.
Nazwa relacji oraz nazwane podzbiory powinny być rozdzielone dwukropkiem.
Nazwane podzbiory mogą również zostać zdefiniowane w opcji `with` reguły relacyjnej zadeklarowanej
w [CActiveRecord::relations()]. W następnym przykładzie, jeśli odczytamy `$user->posts`,
zwróci nam wszystkie zatwierdzone komentarze (*approved*) postu.
[php]
class User extends CActiveRecord
{
public function relations()
{
return array(
'posts'=>array(self::HAS_MANY, 'Post', 'author_id',
'with'=>'comments:approved'),
);
}
}
~~~
> Note|Uwaga: Nazwane podzbiory zastosowane dla modelów w relacji muszą zostać określone
w [CActiveRecord::scopes]. W rezultacie, nie mogą one zostać sparametryzowane.
<div class="revision">$Id: database.arr.txt 2782 2010-12-28 16:18:06Z qiang.xue $</div>