Doctrine DQL,类表继承和对子类字段的访问

时间:2011-12-13 21:45:11

标签: php inheritance doctrine-orm doctrine dql

我遇到DQL查询和实体专业化问题。

我有一个名为Auction的实体,与OneToOneItem关系。 ItemmappedSuperclassFilm的{​​{1}}。我需要一个可以支持搜索引擎的查询,允许用户查找具有不同属性Book的具有不同属性的项目的拍卖(AND部分使其具有挑战性)。

问题在于即使AND具有指向Auction的关联,我也需要访问Item - 和Film特定字段。用户将指定他们正在寻找的Book类型,但除了在我的DQL查询中使用Item之外,我没有看到任何使用此信息的方法。

到目前为止,我尝试过使用类似的查询:

INSTANCE OF

这样的查询导致错误说:

  

班级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 ...". 没有名为Entities\Item

的字段或关联

bookTypes为false,但Book为真。

我也试过

Item

但我认为Doctrine要求我在SELECT a FROM Entities\Book i INNER JOIN i.auction a ... SELECT语句中引用相同的实体。

如果这很重要,我正在使用类表继承。不过,我认为切换到单表继承不会起到作用。

有什么想法吗?

5 个答案:

答案 0 :(得分:10)

正如Matt所说,这是Doctrine Project无法解决的一个老问题(DDC-16)。

问题在于,学说的DQL是一种静态类型的语言,其内部结构具有一定的复杂性。

我们考虑过多次允许向上转换,但是努力实现这项工作根本不值得,人们只会滥用语法做非常危险的事情。

正如DDC-16所述,确实无法理解属性属于哪个类而不会产生令人讨厌的问题,例如多个子类定义具有不同列名的相同属性。

如果要在CTI或JTI中过滤子类中的数据,可以使用我在https://stackoverflow.com/a/14854067/347063中描述的技术。这将您的DQL与所有涉及的子类相结合。

您的案例中最需要的DQL(假设Entities\BookEntities\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'
    )

这是您的问题的伪代码。这并不好,但请记住,SQL和DQL是非常不同的,并遵循不同的规则。

答案 1 :(得分:4)

<强>更新

我发现了一个解决方案。请参阅我对这个相关问题的回答:

Doctrine2: Polymorphic Queries: Searching on properties of subclasses

答案 2 :(得分:2)

Doctrine团队表示他们不会为此添加支持:

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

该页面的相关评论:

  

这确实很棘手。然而,单独的语法可能永远不会起作用,   因为可能有几个子类有一个名为&#34; d&#34;的字段,   所以学说不知道你的意思。


  

我正在关闭这个。

     

这个问题的要求基本上违反了面向对象的原则。

     

如果你真的需要过滤你的多个子实体   继承,然后尝试以下代码:

     

选择       r FROM       根r WHERE       r.id IN(           选择               c.id           从               孩子c           哪里               c.field =:价值       )

答案 3 :(得分:2)

您可以通过使用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...

或使用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');

这是基于Ian Philips在问题here

中给出的答案

答案 4 :(得分:0)

我遇到了同样的问题,并且没有为每个子类使用单独的查询并在以后的应用程序级别合并它们时找不到解决方案。

有一点我敢肯定,单表继承不会解决这个问题,完全相同。

还有另一种选择,虽然逻辑上很脏。 定义超类中的所有字段(您需要的字段)。如果记录逻辑上没有该字段,则它将为空。不是一个漂亮的景象,但嘿,比2-3-4 -...查询更优化。同样在这种情况下,单表继承肯定是更好的方法