update delete php doctrine dql

php - delete - find symfony doctrine



Doctrine 2 DQL: ¿cómo seleccionar el lado inverso de la consulta unidireccional de muchos a muchos? (5)

Creo que también debe seleccionar SiteVersion en su consulta:

SELECT v, p FROM SiteVersion v JOIN v.pages p WHERE v.id = 5 AND p.slug=''index''

Obtendrá una matriz de entidades de SiteVersion con las que puede recorrer para obtener las entidades de la Página.

Tengo dos clases: Page y SiteVersion, que tienen una relación de muchos a muchos. Solo SiteVersion es consciente de la relación (porque el sitio es modular y quiero poder quitar y colocar el módulo al que pertenece SiteVersion).

¿Cómo seleccionaría las páginas según los criterios de SiteVersion?

Por ejemplo, esto no funciona:

SELECT p FROM SiteVersion v JOIN v.pages p WHERE v.id = 5 AND p.slug=''index''

Me sale el error

[Doctrine/ORM/Query/QueryException] [Semantical Error] line 0, col -1 near ''SELECT p FROM'': Error: Cannot select entity through identification variables without choosing at least one root entity alias.

Aunque puedo seleccionar "v" con esta consulta.

Creo que posiblemente podría resolver esto introduciendo una clase para la relación (una clase de PageToVersion) pero ¿hay alguna forma sin hacer eso, o hacerlo bidireccional?


Hay dos formas de manejar esto en Doctrine ORM. El más típico es usar una condición IN con una subconsulta:

SELECT p FROM SitePage p WHERE p.id IN( SELECT p2.id FROM SiteVersion v JOIN v.pages p2 WHERE v.id = :versionId AND p.slug = :slug )

La otra forma es con una unión adicional con la funcionalidad de unión arbitraria introducida en la versión 2.3 del ORM :

SELECT p FROM SitePage p JOIN SiteVersion v WITH 1 = 1 JOIN v.pages p2 WHERE p.id = p2.id AND v.id = :versionId AND p2.slug = :slug

El 1 = 1 es solo debido a una limitación actual del analizador.

Tenga en cuenta que la limitación que causa el error semántico se debe a que el proceso de hidratación se inicia desde la raíz de las entidades seleccionadas. Sin una raíz en su lugar, el hidratador no tiene ninguna referencia sobre cómo colapsar los resultados de fetch-joined o unir.


He encontrado una posible solución para este problema here .

De acuerdo con esa página, su consulta debe verse algo como esto:

SELECT p FROM SiteVersion v, Page p WHERE v.id = 5 AND p.slug=''index'' AND v.page = p;

¿Resuelve tu problema?


No pude averiguar cómo hacer que funcionen las consultas nativas, así que resolví de una manera un poco intrincada:

$id = $em->getConnection()->fetchColumn("SELECT pages.id FROM pages INNER JOIN siteversion_page ON siteversion_page.page_id = pages.id INNER JOIN siteversions ON siteversion_page.siteversion_id = siteversions.id WHERE siteversions.id = 1 AND pages.slug = ''index''"); $page = $em->find(''Page'', $id);

No me gusta porque da como resultado más consultas a la base de datos (especialmente si necesito buscar un conjunto de páginas en lugar de una) pero funciona.

Edit : He decidido ir solo con una clase para la asociación. Ahora puedo hacer esta consulta:

SELECT p FROM Page p, SiteVersionPageLink l WHERE l.page = p AND l.siteVersion = 5 AND p.slug = ''index''


Prueba esto (o algo parecido):

SELECT p FROM Page p WHERE EXISTS (SELECT v FROM SiteVersion v WHERE p MEMBER OF v.pages AND v.id = 5 AND p.slug = ''index'')

No he probado esto exactamente, pero he conseguido algo similar para trabajar. El uso de EXISTS y MEMBER OF están ocultos en la sección de ejemplos de selección de DQL del capítulo de DQL.