Mysql
 sql >> Base de données >  >> RDS >> Mysql

Est-il possible d'utiliser le résultat d'une fonction SQL comme champ dans Doctrine ?

Vous pouvez mapper un résultat d'une seule colonne vers un champ d'entité - regardez requêtes natives et ResultSetMapping pour y parvenir. Comme exemple simple :

use Doctrine\ORM\Query\ResultSetMapping;

$sql = '
    SELECT p.*, COUNT(r.id)
    FROM products p
    LEFT JOIN reviews r ON p.id = r.product_id
';

$rsm = new ResultSetMapping;
$rsm->addEntityResult('AppBundle\Entity\Product', 'p');
$rsm->addFieldResult('p', 'COUNT(id)', 'reviewsCount');

$query   = $this->getEntityManager()->createNativeQuery($sql, $rsm);
$results = $query->getResult();

Ensuite, dans votre entité Produit, vous auriez un $reviewsCount champ et le nombre serait mappé à cela. Notez que cela ne fonctionnera que si vous avez une colonne définie dans les métadonnées Doctrine, comme ceci :

/**
 * @ORM\Column(type="integer")
 */
private $reviewsCount;

public function getReviewsCount()
{
    return $this->reviewsCount;
}

C'est ce que suggère le Champs agrégés Documents doctrinaux. Le problème est ici que vous faites essentiellement croire à Doctrine que vous avez une autre colonne dans votre base de données appelée reviews_count , ce que vous ne voulez pas. Donc, cela fonctionnera toujours sans ajouter physiquement cette colonne, mais si jamais vous exécutez un doctrine:schema:update il va ajouter cette colonne pour vous. Malheureusement, Doctrine n'autorise pas vraiment les propriétés virtuelles, donc une autre solution serait d'écrire votre propre hydrateur personnalisé, ou peut-être de vous abonner au loadClassMetadata événement et ajoutez manuellement le mappage vous-même après le chargement de votre (ou vos) entité(s) particulière(s).

Notez que si vous faites quelque chose comme COUNT(r.id) AS reviewsCount alors vous ne pouvez plus utiliser COUNT(id) dans votre addFieldResult() et doit utiliser à la place l'alias reviewsCount pour ce second paramètre.

Vous pouvez également utiliser le ResultSetMappingBuilder pour commencer à utiliser le mappage de l'ensemble de résultats.

Ma suggestion actuelle est de le faire manuellement au lieu de passer par toutes ces choses supplémentaires. Créez essentiellement une requête normale qui renvoie à la fois vos résultats d'entité et scalaires dans un tableau, puis définissez le résultat scalaire sur un champ correspondant non mappé sur votre entité, et renvoyez l'entité.