Doctrine2:[语义错误] 不能通过标识变量选择实体而不选择至少一个根实体别名

Posted

技术标签:

【中文标题】Doctrine2:[语义错误] 不能通过标识变量选择实体而不选择至少一个根实体别名【英文标题】:Doctrine2: [Semantical Error] Cannot select entity through identification variables without choosing at least one root entity alias 【发布时间】:2016-06-11 15:27:57 【问题描述】:

这是我使用查询生成器的查询,它运行良好,带来了用户表和模块表的所有结果,它们具有多对多关联:

public function getUser($id)
    $qb = $this->getEm()->createQueryBuilder()
    ->select('u', 'm')
    ->from('Adm\Entity\User', 'u')
    ->join('u.modules', 'm')
    ->where('u.id = ?1')
    ->setParameters(array(1 => $id));
    $result = $qb->getQuery()->getResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);
    return $result;

但是当我尝试像这样从用户中选择特定字段时:

public function getUser($id)
    $qb = $this->getEm()->createQueryBuilder()
    ->select('u.id, u.name, u.email', 'm')
    ->from('Adm\Entity\User', 'u')
    ->join('u.modules', 'm')
    ->where('u.id = ?1')
    ->setParameters(array(1 => $id));
    $result = $qb->getQuery()->getResult(\Doctrine\ORM\AbstractQuery::HYDRATE_ARRAY);
    return $result;

Doctrine 抛出错误:

[Semantical Error] line 0, col -1 near 'SELECT u.id,': Error: Cannot select entity through identification variables without choosing at least one root entity alias.

我想知道如何做到这一点,从实体中选择特定字段而不是所有字段。

【问题讨论】:

【参考方案1】:

第二个查询的问题是您试图返回关联的 modules 对象,而不是 User 对象。教义不喜欢这样,也不这样运作。我知道您尝试对数组进行水合,但如果您没有这样做,这就是您的第一个查询将尝试返回的内容:

User object 
    ...,
    $modules -> array of Module objects

因此,您将返回单个 User 对象,然后该 User 类的 $modules 成员将成为所有关联模块对象的数组。即使你选择了u, m,Doctrine 仍然想要返回那个对象,因为m 只是u 上的一个关联。仅仅因为您想要对数组进行水合并不会改变 Doctrine 选择数据的方式。

您的第二个示例 - Doctrine 不知道如何返回它。通过单独选择用户字段,您将不再返回一个用户对象,而是一个用户值数组。那么,它甚至可以在哪里返回相关的模块呢?返回这种格式没有意义:

[
    user id,
    user name,
    user email,
    [ array of Module objects ]
]

这作为多对多关联更加棘手。真正的问题是,你想用你的第二个查询来完成什么,而你发现你的第一个查询是不可接受的?如果是性能,您可能不会从第二个查询中获得太多收益。如果它只是返回特定的列,那么您也应该指定那些 m. 列。

【讨论】:

嗨@Jason Roman,感谢您的出色回答。我的第二个查询是由于我不想从用户表/实体中获取所有字段,例如:密码,因为我在 javascript 中使用此查询,它将在浏览器控制台中公开。 听起来不错 - 然后只需确保选择您需要的各个列,而不仅仅是用户实体。您还可以查看 JMSSerializerBundle github.com/schmittjoh/JMSSerializerBundle,以更好地了解您返回的内容......例如,您可以使用 @Exclude 标记您的密码字段。见:github.com/schmittjoh/JMSSerializerBundle 感谢@Jason Roman 的提示,如果我尝试做这样的事情:->select('u.id, u.name', 'm.id, m.name') 查询给我带来了来自 'm' 的第一个结果,不像 ->select('u.', ' m') 给我带来正确的数组的'm'。 有趣 - 在你的情况下,我会运行原生 SQL 调用并返回该结果,或者,使用你的第一次尝试并使用我描述的序列化程序排除不需要的字段 谢谢@Jason Roman,我会试试序列化器和原生 SQL。

以上是关于Doctrine2:[语义错误] 不能通过标识变量选择实体而不选择至少一个根实体别名的主要内容,如果未能解决你的问题,请参考以下文章

语法和语义和错误;

Amazon Mechanical Turk 中人群语义分割小部件的初始值属性出现错误标识符错误

Python标识符和关键字

Doctrine2重复键名错误

zf2 + 学说 2 上的用户定义函数不起作用

2.6 C#的标识符命名规则