Eğer ne yaptığınızı bilmiyorsanız, doctrinenin lazy load özelliği kötü sonuçlara sebep olabilir. Bu özellik varsayılan olarak aktif haldedir, bu nedenle kendi sorgularımızı kendimiz kontrol altında tutmamız gerekir. Size vereceğim en iyi tavsiye, eğer sorgunuz içinde farklı tablo ilişkileri var ise, repository class yaratıp DQL sorgusunu kendiniz yazın. Örneğin; bir Country (Ülke) sıfır veya birden fazla League (Lig) barındırabileceği için, bu 1-N ilişkidir. Şimdi aşağıdaki örneğe bakalım.


1-N varlık ilişkisi


# Country entity

/**
* @ORM\Entity
* @ORM\Table(name="country")
*/
class Country
{
protected $id;
protected $code;
protected $name;
protected $createdAt;
protected $updatedAt;

/**
* @ORM\OneToMany(
* targetEntity="League",
* mappedBy="country",
* cascade={"persist", "remove"},
* orphanRemoval=true
* )
*/
protected $league;
.......
}

# League entity

/**
* @ORM\Entity
* @ORM\Table(name="league")
*/
class League
{
protected $id;
protected $name;
protected $createdAt;
protected $updatedAt;

/**
* @ORM\ManyToOne(
* targetEntity="Country",
* inversedBy="league"
* )
* @ORM\JoinColumn(
* name="country_id",
* referencedColumnName="id",
* onDelete="CASCADE",
* nullable=false
* )
*/
protected $country;
.......
}

Örnek veriler


mysql> SELECT * FROM country;
+----+----------------+---------------------+------------+------+
| id | name | created_at | updated_at | code |
+----+----------------+---------------------+------------+------+
| 28 | Germany | 2015-05-16 19:59:00 | NULL | DE |
| 29 | Spain | 2015-05-16 19:59:00 | NULL | ES |
| 30 | Turkey | 2015-05-16 19:59:00 | NULL | TR |
| 31 | United Kingdom | 2015-05-16 21:39:25 | NULL | GB |
+----+----------------+---------------------+------------+------+
4 rows in set (0.00 sec)

mysql> SELECT * FROM league;
+----+------------+-------------------+---------------------+------------+
| id | country_id | name | created_at | updated_at |
+----+------------+-------------------+---------------------+------------+
| 6 | 28 | Bundesliga | 2015-05-16 19:59:00 | NULL |
| 7 | 29 | Primera División | 2015-05-16 19:59:00 | NULL |
| 8 | 29 | Segunda División | 2015-05-16 19:59:00 | NULL |
| 9 | 30 | Süper Lig | 2015-05-16 19:59:00 | NULL |
| 10 | 30 | TFF 1. Lig | 2015-05-16 19:59:00 | NULL |
| 11 | 31 | Premier League | 2015-05-16 19:59:00 | NULL |
+----+------------+-------------------+---------------------+------------+
6 rows in set (0.00 sec)

Country - kötü versiyon


Buna "kötü" dememizin nedeni, ana varlık ile birlikte lazy load ile alakalı varlığa da ulaşacağız. Mevcut olan findAll() doctrine fonksiyonunu kullanacağız. İyi kontrol edilmeyen lazy load, $c->getLeague()->first()->getName() ve {{ country.getLeague.first.name }} satırları için extra sorgulama yapar. Bu işlem sonuç olarak toplam 5 tane sorgulama yapar. 1 tanesi ülkeleri seçmek için, 1'er tanede tüm ülkelerin ilk liglerini seçmek için.


# Country controller

class CountryController
{
public function listAction()
{
$repo = $this->getDoctrine()->getRepository('FootballFrontendBundle:Country');

$country = $repo->findAll();

// foreach ($country as $c) {
// $id = $c->getId();
// $code = $c->getCode();
// // ....
// $league = $c->getLeague()->first()->getName();
// }

return $this->render(
'FootballFrontendBundle:Country:list.html.twig', ['countryArray' => $country]
);
}
}

# FootballFrontendBundle:Country:list.html.twig

{% if countryArray is defined and countryArray|length != 0 %}
<table border="1px">
<tr>
<td>#</td>
<td>ID</td>
<td>CODE</td>
<td>NAME</td>
<td>CREATED</td>
<td>UPDATED</td>
<td>LEAGUE</td>
</tr>
{% for country in countryArray %}
<tr>
<td class="head">{{ loop.index }}</td>
<td>{{ country.id }}</td>
<td>{{ country.code }}</td>
<td>{{ country.name }}</td>
<td>{{ country.createdAt|date('d/m/Y H:i:s') }}</td>
<td>{{ country.updatedAt is not null ? country.updatedAt|date('d/m/Y H:i:s') : '' }}</td>
<td>{{ country.getLeague.first.name }}</td>
</tr>
{% endfor %}
</table>
{% else %}
No country found in database!
{% endif %}

Country - iyi versiyon


Burada kendi repository classımızı yaratıp, ilgili ligleride seçebilmek için, kendi findAll() fonksiyonumuzu yaratacağız. Bu yöntemle yukarıdaki işlem toplam 1 tane sorgulama yapacaktır. Aşağıdaki çıktı her iki yöntem için de geçerlidir.


# Country repository

class CountryRepository extends EntityRepository
{
public function findAll()
{
return
$this->createQueryBuilder('c')
->select('c, l')
->leftJoin('c.league', 'l')
->getQuery()
->getResult();
}
}

Çıktı



League - kötü versiyon


Yukarıdaki yorumlar bu bölüm için de geçerlidir. İyi kontrol edilmeyen lazy load, $l->getCountry()->getName() ve {{ league.country.name }} satırları için extra sorgulama yapar. Bu işlem sonuç olarak toplam 5 tane sorgulama yapar. 1 tanesi ligleri seçmek için, 1'er tanede tüm liglerin ülkelerini seçmek için.


# League controller

class LeagueController
{
public function listAction()
{
$repo = $this->getDoctrine()->getRepository('FootballFrontendBundle:League');

$league = $repo->findAll();

// foreach ($league as $l) {
// $id = $l->getId();
// $name = $l->getName();
// // ...
// $countryName = $l->getCountry()->getName();
// }

return $this->render(
'FootballFrontendBundle:League:list.html.twig', ['leagueArray' => $league]
);
}
}

# FootballFrontendBundle:League:list.html.twig

{% if leagueArray is defined and leagueArray|length != 0 %}
<table border="1px">
<tr>
<td>#</td>
<td>ID</td>
<td>NAME</td>
<td>CREATED</td>
<td>UPDATED</td>
<td>COUNTRY</td>
</tr>
{% for league in countryArray %}
<tr>
<td class="head">{{ loop.index }}</td>
<td>{{ league.id }}</td>
<td>{{ league.name }}</td>
<td>{{ league.createdAt|date('d/m/Y H:i:s') }}</td>
<td>{{ league.updatedAt is not null ? league.updatedAt|date('d/m/Y H:i:s') : '' }}</td>
<td>{{ league.country.name }}</td>
</tr>
{% endfor %}
</table>
{% else %}
No league found in database!
{% endif %}

League - iyi versiyon


Burada kendi repository classımızı yaratıp, ilgili ülkeleri seçebilmek için, kendi findAll() fonksiyonumuzu yaratacağız. Bu yöntemle yukarıdaki işlem toplam 1 tane sorgulama yapacaktır. Aşağıdaki çıktı her iki yöntem için de geçerlidir.


# League repository

class LeagueRepository extends EntityRepository
{
public function findAll()
{
return
$this->createQueryBuilder('l')
->select('l, c')
->leftJoin('l.country', 'c')
->getQuery()
->getResult();
}
}

Çıktı