php - español - Doctrine DQL, herencia de tabla de clase y acceso a campos de subclases
find symfony doctrine (5)
Tengo un problema con una consulta de DQL y la especialización de entidades.
Tengo una entidad llamada Auction
, que es OneToOne
relación OneToOne
con el Item
. Item
es una mappedSuperclass
para la Film
y el Book
. Necesito una consulta que pueda respaldar un motor de búsqueda, lo que permite al usuario buscar subastas con diferentes propiedades AND
vender artículos con diferentes propiedades (es la parte AND
que lo hace un desafío).
El problema es que a pesar de que Auction
tiene una asociación que apunta a Item
como tal, necesito tener acceso a campos específicos de Film
y Book
. Los usuarios especificarán el tipo de Item
que están buscando, pero no veo otra forma de usar esta información que no sea usar INSTANCE OF
en mi consulta de DQL.
Hasta ahora, he intentado usar una consulta como:
SELECT a FROM Entities/Auction a
INNER JOIN a.item i
INNER JOIN i.bookTypes b
WHERE i INSTANCE OF Entities/Book
AND b.type = ''Fantasy''
AND ...".
Tal consulta da como resultado un error que dice que:
Entities/Item
claseEntities/Item
no tiene ningún campo o asociación llamadabookTypes
lo cual es falso para el Book
, pero verdadero para el Item
.
Tambien lo he intentado
SELECT a FROM Entities/Book i
INNER JOIN i.auction a ...
pero reconozco que Doctrine requiere que me refiera a la misma Entidad en las declaraciones SELECT
y FROM
.
Si eso es importante, estoy usando la herencia de tabla de clases. Aún así, no creo que cambiar a la herencia de una sola tabla haga el truco.
¿Algunas ideas?
Como dijo Matt, este es un problema antiguo que Doctrine Project no solucionará ( DDC-16 ).
El problema es que el DQL de doctrine es un lenguaje estáticamente tipado que viene con cierta complejidad en sus aspectos internos.
Pensamos en permitir un alto nivel de emisión un par de veces, pero el esfuerzo por lograrlo no vale la pena, y la gente simplemente abusaría de la sintaxis haciendo cosas muy peligrosas.
Como se indica en DDC-16, tampoco es posible entender a qué clase pertenece la propiedad sin incurrir en problemas desagradables, como varias subclases que definen las mismas propiedades con diferentes nombres de columna.
Si desea filtrar datos en subclases en un CTI o JTI, puede utilizar la técnica que he descrito en https://.com/a/14854067/347063 . Que une tu DQL con todas las subclases involucradas.
El DQL que necesitarías en tu caso es más probable (asumiendo que Entities/Book
es una subclase de Entities/Item
):
SELECT
a
FROM
Entities/Auction a
INNER JOIN
a.item i
INNER JOIN
i.bookTypes b
WHERE
i.id IN (
SELECT
b.id
FROM
Entities/Book b
WHERE
b.type = ''Fantasy''
)
Ese es el pseudocódigo para tu problema. No está bien, pero tenga en cuenta que SQL y DQL son muy diferentes y siguen reglas diferentes.
El equipo de Doctrine ha declarado que no van a agregar soporte para esto:
Comentarios pertinentes de esa página:
Eso es realmente complicado. Sin embargo, esa sintaxis por sí sola nunca puede funcionar, ya que puede haber varias subclases que tengan un campo llamado "d", por lo que Doctrine no sabría a qué campo se refiere.
Estoy cerrando este.
El requisito de este problema es básicamente violar los principios OO.
Si realmente necesita filtrar a través de varias entidades secundarias en su herencia, intente algo como lo siguiente:
SELECCIONE r DE Raíz r WHERE r.id IN (SELECCIONE c.id FROM Child c DONDE c.field =: valor)
Puede resolverlo fácilmente uniendo a la izquierda su entidad base con su clase de herencia utilizando el id:
SELECT a FROM Entities/Auction a
INNER JOIN a.item i
INNER JOIN Entities/Book b WITH b.id = i.id
INNER JOIN b.bookTypes bt
WHERE bt.type = ''Fantasy''
AND...
o con un queryBuilder:
$queryBuilderb->select(''a'')
->from(''Entities/Auction'', ''a'')
->innerJoin(''a.item'', ''i'')
->innerJoin(''Entities/Book'', ''b'', ''WITH'', ''b.id = i.id'')
->innerJoin(''b.bookTypes'', ''bt'')
->where(''bt.type = :type'')
->andWhere(...
->setParameter(''type'', ''Fantasy'');
Esto se basa en la respuesta dada por Ian Philips en la pregunta here
Tuve el mismo problema y no encontré una solución sin usar consultas separadas para cada subclase y fusionarlas más adelante en el nivel de la aplicación.
De una cosa estoy seguro, la herencia de una sola tabla no resolverá esto, completamente lo mismo.
Hay otra alternativa, aunque esté lógicamente sucia. Defina todos los campos (los que necesita) en la superclase. Si el registro no tiene lógicamente ese campo, estará vacío. No es una vista bonita, pero bueno, más optimizada que las consultas 2-3-4 -... También en este caso, la herencia de una sola tabla es definitivamente la mejor manera de hacerlo.
Actualizado:
He descubierto una solución para esto. Vea mi respuesta para esta pregunta relacionada:
Doctrine2: Consultas polimórficas: Búsqueda de propiedades de subclases