Table des matières
Un NativeQuery vous permet d'exécuter des instructions SQL SELECT natale, la cartographie des résultats en fonction de vos spécifications. Une telle spécification qui décrit comment un jeu de résultats SQL est mappée à un résultat doctrine est représentée par un resultSetMapping. Il décrit comment chaque colonne du résultat de bases de données devraient être cartographiés par Doctrine en termes d'objet graphique. Cela vous permet de cartographier du code SQL arbitraire d'objets, tels que des fournisseurs hautement optimisé SQL ou procédures stockées.
Si vous voulez exécuter DELETE, UPDATE ou INSERT déclarations du SQL natif, l'API ne peut pas être utilisé et probablement générérera des erreurs. Utilisez EntityManager#getConnection() pour accéder à la connexion base de données native et appeler la méthode executeUpdate() pour ces requêtes.
Pour créer un NativeQuery vous utilisez la méthode EntityManager#createNativeQuery($sql, $resultSetMapping). Comme vous pouvez le voir dans la signature de cette méthode, elle s'attend à deux ingrédients: le SQL que vous voulez exécuter et le resultSetMapping qui décrit comment les résultats seront cartographiés.
Une fois que vous avez obtenu une instance d'une NativeQuery, vous pouvez lier des paramètres à lui et finalement de l'exécuter.
Comprendre les resultSetMapping est la clé de l'aide d'un NativeQuery. Un résultat Doctrine peut contenir les éléments suivants:
Il pourrait ne pas vous surprendre que Doctrine utilise resultSetMapping en interne lorsque vous créez des requêtes DQL. Comme la requête obtenue est analysée et transformée en SQL, Doctrine crait un resultSetMapping qui décrit comment les résultats doivent être traitées par les routines de l'hydratation.
Nous allons maintenant examiner chacun des types de résultats qui peuvent apparaître dans une resultSetMapping en détail.
Un résultat entité décrit un type d'entité qui apparaît comme un élément racine dans le résultat transformé. Vous ajoutez un résultat entité par ResultSetMapping#addEntityResult(). Jettons un oeil à la signature de la méthode en détail:
<?php /** * Adds an entity result to this ResultSetMapping. * * @param string $class The class name of the entity. * @param string $alias The alias for the class. The alias must be unique among all entity * results or joined entity results within this ResultSetMapping. */ public function addEntityResult($class, $alias)
Le premier paramètre est le nom entièrement qualifié de la classe d'entité. Le deuxième paramètre est quelques alias arbitraire pour Le résultat entité qui doit être unique dans une resultSetMapping. Vous utilisez cet alias pour attacher des résultats de champ au résultat entité. Il est très similaire à une variable d'identification que vous utilisez dans DQL d'alias classes ou des relations.
Un résultat entité seule ne suffit pas à former un resultSetMapping valide. lE résultat a toujours besoin d'un ensemble de résultats de champ, que nous examinerons bientôt.
Le résultat décrit un type d'entité qui apparaît comme un élément relation joint dans le résultat transformé, attaché à un résultat entité (root). Vous ajoutez un résultat par le biais ResultSetMapping#addJoinedEntityResult(). Jetons un oeil à la signature de la méthode en détail:
<?php /** * Adds a joined entity result. * * @param string $class The class name of the joined entity. * @param string $alias The unique alias to use for the joined entity. * @param string $parentAlias The alias of the entity result that is the parent of this joined result. * @param object $relation The association field that connects the parent entity result with the joined entity result. */ public function addJoinedEntityResult($class, $alias, $parentAlias, $relation)
Le premier paramètre est le nom de classe de l'entité a rejoint. Le second paramètre est un alias arbitraire pour les entités qui doivent être jointes au sein du resultSetMapping. Vous utilisez cet alias pour attacher les résultats sur le champ au résultat entité. Le troisième paramètre est le pseudonyme du résultat entité qui est le type de la relation parent jointe. Le quatrième et dernier paramètre est le nom du champ sur le résultat entité parent qui doit contenir le résultat de l'entité jointe.
Un résultat de champ décrit le mappage d'une seule colonne dans un résultat SQL jeu à un champ dans une entité. En tant que tel, les résultats sur le champ sont intrinsèquement liés aux résultats entité. Vous ajoutez un résultat sur le champ grâce à ResultSetMapping#addFieldResult().Encore une fois, nous allons examiner la signature de la méthode en détail:
<?php /** * Adds a field result that is part of an entity result or joined entity result. * * @param string $alias The alias of the entity result or joined entity result. * @param string $columnName The name of the column in the SQL result set. * @param string $fieldName The name of the field on the (joined) entity. */ public function addFieldResult($alias, $columnName, $fieldName)
Le premier paramètre est l'alias du résultat entité à laquelle appartiendra le résultat sur le champ. Le deuxième paramètre est le nom de la colonne dans le jeu de résultats SQL. Notez que ce nom est sensible à la casse, c'est à dire si vous utilisez une requête native comme Oracle il doit être en majuscules. Le troisième paramètre est le nom du champ sur le résultat d'une entité identifiées par $alias dans laquelle la valeur de la colonne devrait être fixé.
Un résultat scalaire décrit le mappage d'une seule colonne dans un résultat SQL fixé à une valeur scalaire dans le résultat Doctrine. Les résultats scalaires sont généralement utilisés pour les valeurs agrégées, mais une colonne dans le jeu de résultats SQL peut être mappé comme une valeur scalaire. Pour ajouter un usage résultat scalaire ResultSetMapping#addScalarResult(). La signature de la méthode en détail:
<?php /** * Adds a scalar result mapping. * * @param string $columnName The name of the column in the SQL result set. * @param string $alias The result alias with which the scalar result should be placed in the result structure. */ public function addScalarResult($columnName, $alias)
Le premier paramètre est le nom de la colonne dans le jeu de résultats SQL et le deuxième paramètre est le pseudonyme sous lequel le résultat valeur de la colonne sera placée dans le résultat Doctrine transformé.
Un résultat méta décrit une seule colonne dans un jeu de résultats SQL qui est soit une clé étrangère ou une colonne discriminante. Ces colonnes sont essentiels pour la Doctrine de bien construire des objets à des jeux de résultats SQL. Pour ajouter une colonne comme une utilisation résultat méta ResultSetMapping#addMetaResult(). La signature de la méthode en détail:
<?php /** * Adds a meta column (foreign key or discriminator column) to the result set. * * @param string $alias * @param string $columnAlias * @param string $columnName */ public function addMetaResult($alias, $columnAlias, $columnName)
Le premier paramètre est le pseudonyme du résultat entité à laquelle appartient la colonne méta. Une colonne de résultat méta (clé étrangère ou colonne discriminante) appartient toujours à un résultat entité. Le second paramètre est l'alias de colonne/nom de la colonne dans le jeu de résultats SQL et le troisième paramètre est le nom de la colonne utilisée dans la cartographie.
Lorsque vous rejoignez un arbre d'héritage que vous avez à donner une indication qui Doctrine méta-colonne est la colonne discriminante de cet arbre.
<?php /** * Sets a discriminator column for an entity result or joined entity result. * The discriminator column will be used to determine the concrete class name to * instantiate. * * @param string $alias The alias of the entity result or joined entity result the discriminator * column should be used for. * @param string $discrColumn The name of the discriminator column in the SQL result set. */ public function setDiscriminatorColumn($alias, $discrColumn)
Comprendre un resultSetMapping est probablement plus facile grâce à quelques exemples.
D'abord un exemple de base qui décrit le mappage d'une entité unique.
<?php // Equivalent DQL query: "select u from User u where u.name=?1" // User owns no associations. $rsm = new ResultSetMapping; $rsm->addEntityResult('User', 'u'); $rsm->addFieldResult('u', 'id', 'id'); $rsm->addFieldResult('u', 'name', 'name'); $query = $this->_em->createNativeQuery('SELECT id, name FROM users WHERE name = ?', $rsm); $query->setParameter(1, 'romanb'); $users = $query->getResult();
array( [0] = > User (Object) )
Notez que ce serait un objet partiel si l'entité a plus de champs que juste id et nom. Dans l'exemple ci-dessus les noms des colonnes et sur le champ sont identiques mais ce n'est pas nécessaire, bien sûr. A noter également que la chaîne de requête passée à createNativeQuery est natif SQL. Doctrine ne touche pas à ce SQL en aucune façon.
Dans l'exemple précédent de base, un utilisateur n'a pas de relations et la table de la classe mappée ne possède pas de clés étrangères. L'exemple suivant suppose que l'utilisateur dispose d'une association uni ou bidirectionnelle à une CmsAddress, où l'utilisateur est le côté posséder et possède donc la clé étrangère.
<?php // Equivalent DQL query: "select u from User u where u.name=?1" // User owns an association to an Address but the Address is not loaded in the query. $rsm = new ResultSetMapping; $rsm->addEntityResult('User', 'u'); $rsm->addFieldResult('u', 'id', 'id'); $rsm->addFieldResult('u', 'name', 'name'); $rsm->addMetaResult('u', 'address_id', 'address_id'); $query = $this->_em->createNativeQuery('SELECT id, name, address_id FROM users WHERE name = ?', $rsm); $query->setParameter(1, 'romanb'); $users = $query->getResult();
Les clés étrangères sont utilisées par la doctrine à fin de lazy-loading lors de l'interrogation des objets. Dans l'exemple précédent, chaque objet utilisateur dans le résultat aura un proxy (un «ghost») à la place de l'adresse qui contient le address_id. Lorsque le proxy ghost est accessible, il se charge basée sur cette clé.
En conséquence, les associations qui sont fetch-joined ne requièrent pas que les clés étrangères d'être soient présentes dans le jeu de résultats SQL, seules les associations qui sont à chargement retardé.
<?php // Equivalent DQL query: "select u from User u join u.address a WHERE u.name = ?1" // User owns association to an Address and the Address is loaded in the query. $rsm = new ResultSetMapping; $rsm->addEntityResult('User', 'u'); $rsm->addFieldResult('u', 'id', 'id'); $rsm->addFieldResult('u', 'name', 'name'); $rsm->addJoinedEntityResult('Address' , 'a', 'u', 'address'); $rsm->addFieldResult('a', 'address_id', 'id'); $rsm->addFieldResult('a', 'street', 'street'); $rsm->addFieldResult('a', 'city', 'city'); $sql = 'SELECT u.id, u.name, a.id AS address_id, a.street, a.city FROM users u ' . 'INNER JOIN address a ON u.address_id = a.id WHERE u.name = ?'; $query = $this->_em->createNativeQuery($sql, $rsm); $query->setParameter(1, 'romanb'); $users = $query->getResult();
Dans ce cas, l'entité Adresse imbriqué est enregistré avec la méthode ResultSetMapping#addJoinedEntityResult, qui notifie la doctrine que cette entité n'est pas hydraté au niveau des racines, mais comme une entité rejoint quelque part dans le graphe d'objets. Dans ce cas, nous spécifions l'alias «u» en tant que troisième et quatrième paramètre adresse, ce qui signifie que l'adresse est hydraté dans la propriété User::$address
Si une entité extraite est partie d'une hiérarchie mappée qui nécessite une colonne discriminante, cette colonne doit être présente dans l'ensemble de résultat comme une colonne de telle sorte que la doctrine méta pouvez créer le type approprié de béton. Ceci est illustré dans l'exemple suivant où nous supposons qu'il y a un ou plusieurs sous-classes qui étendent l'utilisateur et non l'Héritage de Table classe ou d'un héritage à table unique est utilisé pour cartographier la hiérarchie (à la fois utiliser une colonne discriminante).
<?php // Equivalent DQL query: "select u from User u where u.name=?1" // User is a mapped base class for other classes. User owns no associations. $rsm = new ResultSetMapping; $rsm->addEntityResult('User', 'u'); $rsm->addFieldResult('u', 'id', 'id'); $rsm->addFieldResult('u', 'name', 'name'); $rsm->addMetaResult('u', 'discr', 'discr'); // discriminator column $rsm->setDiscriminatorColumn('u', 'discr'); $query = $this->_em->createNativeQuery('SELECT id, name, discr FROM users WHERE name = ?', $rsm); $query->setParameter(1, 'romanb'); $users = $query->getResult();
Notez que dans le cas de l'Héritage de Table de classe, un exemple que ci-dessus conduirait à des objets partiels, si tous les objets dans le résultat sont en fait un sous-type de l'utilisateur. Lorsque vous utilisez DQL, Doctrine inclut automatiquement les jointures nécessaires pour cette stratégie de mapping, mais avec du SQL natif, il est de votre responsabilité.
Il y a quelques inconvénients avec des requêtes SQL natif. La première est que vous avez à régler toutes les définitions de mappage jeu de résultats si les noms de colonnes du changement. En DQL cela est détecté dynamiquement lorsque la requête est régénéré avec les métadonnées actuelles.
Pour éviter ces tracas, vous pouvez utiliser la classe ResultSetMappingBuilder. Il permet d'ajouter toutes les colonnes d'une entité à un mapping de résultats. Afin d'éviter les affrontements, vous pouvez éventuellement renommer des colonnes spécifiques quand vous faites la même chose dans votre instruction SQL:
<?php $sql = "SELECT u.id, u.name, a.id AS address_id, a.street, a.city " . "FROM users u INNER JOIN address a ON u.address_id = a.id"; $rsm = new ResultSetMappingBuilder($em); $rsm->addRootEntityFromClassMetadata('MyProject\User', 'u'); $rsm->addJoinedEntityFromClassMetadata('MyProject\Address', 'a', 'u', 'address', array('id' => 'address_id'));
Pour les entités avec plusieurs colonnes le constructeur est très pratique à utiliser. Elle étend la classe resultSetMapping et comme tel a toutes les fonctionnalités de celui-ci aussi. Actuellement, le ResultSetMappingBuilder ne supporte pas les entités de l'héritage.