2011-12-13 11 views
18

Tengo un problema con una consulta DQL y especialización de entidad.Doctrine DQL, herencia de tabla de clase y acceso a campos de subclase

Tengo una entidad llamada Auction, que es OneToOne relación con Item. Item es un mappedSuperclass para Film y Book. Necesito una consulta que respalde un motor de búsqueda, lo que permite al usuario buscar subastas con diferentes propiedades AND vendiendo artículos con diferentes propiedades (es la parte AND lo que lo hace difícil).

El problema es que a pesar de que tiene una asociación Auction señalando Item como tal, necesita tener acceso a Film - Book y campos específicos de. Los usuarios especificarán el tipo Item que están buscando, pero no veo ninguna forma de usar esta información más que usando INSTANCE OF en mi consulta 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 resulta en un error diciendo que:

Clase Entities\Item no tiene campo o asociación nombrado bookTypes

que es falso para Book, pero válido para Item.

también he intentado

SELECT a FROM Entities\Book i 
    INNER JOIN i.auction a ... 

pero calculo Doctrina requiere que me refiero a la misma entidad en SELECT y FROM declaraciones.

Si eso es importante, estoy usando la herencia de la tabla de clases. Aún así, no creo que cambiar a la herencia de una sola tabla haría el truco.

¿Alguna idea?

+0

posible duplicado de [Donde-ing en tablas discriminadas] (http://stackoverflow.com/questions/14851602/where-ing-in-discriminated-tables) – Ocramius

Respuesta

9

Como dijo Matt, este es un problema antiguo que Doctrine Project no solucionará (DDC-16).

El problema es que la doctrina de DQL es un lenguaje estáticamente estátizado que viene con una cierta cantidad de complejidad en sus partes internas.

Pensamos en permitir el upcasting un par de veces, pero el esfuerzo para hacer que funcione simplemente 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 saber a qué clase pertenece la propiedad sin incurrir en problemas desagradables como múltiples subclases que definen las mismas propiedades con diferentes nombres de columna.

Si desea filtrar datos en subclases en un CTI o JTI, puede usar la técnica que describí en https://stackoverflow.com/a/14854067/347063. Eso combina su DQL con todas las subclases involucradas.

El DQL que necesitaría en su caso es más probable (suponiendo 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 pseudo-código para su problema. No es agradable, pero tenga en cuenta que SQL y DQL son muy diferentes y siguen reglas diferentes.

0

Tuve el mismo problema y no encontré una solución sin utilizar consultas separadas para cada subclase y fusionarlas más tarde en el nivel de la aplicación.

Una cosa estoy segura, la herencia de una sola mesa no resolverá esto, completamente la misma cosa.

Hay otra alternativa, aunque lógicamente sucia. Defina todos los campos (los que necesita) en la superclase. Si el registro lógicamente no tiene ese campo, estará vacío. No es un espectáculo bonito, pero bueno, más optimizado que 2-3-4 -... consultas. También en este escenario herencia única tabla es sin duda la mejor manera de ir

+2

La fusión de resultados no es exactamente el caso aquí, ya que nunca necesito que las películas y los libros aparezcan en los resultados de mi consulta al mismo tiempo. La solución que finalmente se me ocurrió fue agregar el lado inverso de la relación Artículo de Subasta y la consulta de Artículos en lugar de Subastas ('SELECCIONAR i FROM Entidades \ Libro INNER JOIN i.auction a WHERE (...)') . Como sé qué subclase estoy buscando, puedo construir mi consulta en consecuencia. Gracias por la respuesta, sin embargo, su idea podría ser un buen camino a seguir, ya que parece que no tiene mucho sentido usar la herencia con Doctrine en casos como este. – crizzis

+0

Esa es una idea bastante mala y es más un truco: no es necesario romper los modelos para arreglar el DQL. Como último recurso, siempre puede usar SQL nativo al precio de mantener algunas consultas más. – Ocramius

2

El equipo Doctrina ha declarado que no van a añadir soporte para esto:

http://www.doctrine-project.org/jira/browse/DDC-16

comentarios relevantes a partir de esa página:

Eso es realmente complicado. Sin embargo, esa sintaxis sola nunca puede funcionar, porque puede haber varias subclases que tengan un campo llamado "d", , por lo que Doctrine no sabrá a qué campo se refiere.


estoy cerrando éste.

El requisito de este problema es básicamente la violación de los principios de OO.

Si realmente necesita para filtrar a través de múltiples niño-entidades en su herencia , a continuación, intentar algo como siguiente en su lugar:

SELECT R desde raíz r DONDE r.id IN (SELECT c. Identificación del DE niño c DONDE c.field =: valor )

2

Puede resolver esto mediante la izquierda unirse a su entidad de 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

Cuestiones relacionadas