Doctrine - [语义错误] - 错误:类没有字段或关联

Jim*_*mbo 4 php doctrine-orm

我试图在存储库中运行Doctrine的DQL查询,我收到以下错误:

QueryException.php第63行中的QueryException:[语义错误]第0行,第100行'test_suite_id'附近:错误:类Application\Model\Entity\Page没有名为test_suite_id的字段或关联

协会

A User可以有多个TestSuites.A TestSuite可以有多个Pages.其结果是,我有一个一对多之间的关联UserTestSuite,和TestSuitePage分别.

协会

以下是我的实体,只显示了相关的关联:

用户

/**
 * @ORM\Table(name="users", uniqueConstraints={@ORM\UniqueConstraint(name="unique_email", columns={"email"})})
 * @ORM\Entity(repositoryClass="Application\Model\Repository\UserRepository")
 */
class User
{
    /**
     * @var TestSuite[]
     *
     * @ORM\OneToMany(targetEntity="TestSuite", mappedBy="user", cascade={"all"})
     */
    private $testSuites = [];
}
Run Code Online (Sandbox Code Playgroud)

的TestSuite

/**
 * @ORM\Table(name="test_suites")
 * @ORM\Entity(repositoryClass="Application\Model\Repository\TestSuiteRepository")
 */
class TestSuite
{
    /**
     * @var User
     *
     * @ORM\ManyToOne(targetEntity="User", inversedBy="testSuites")
     * @ORM\JoinColumn{name="user_id", referencedColumnName="id")
     */
    private $user;

    /**
     * @var Page[]
     *
     * @ORM\OneToMany(targetEntity="Page", mappedBy="testSuite", cascade={"all"})
     */
    private $pages = [];

}
Run Code Online (Sandbox Code Playgroud)

/**
 * @ORM\Table(name="pages")
 * @ORM\Entity(repositoryClass="Application\Model\Repository\PageRepository")
 */
class Page
{
    /**
     * @var TestSuite
     *
     * @ORM\ManyToOne(targetEntity="TestSuite", inversedBy="pages")
     * @ORM\JoinColumn(name="test_suite_id", referencedColumnName="id", nullable=false)
     */
    private $testSuite;
}
Run Code Online (Sandbox Code Playgroud)

存储库DQL查询

public function findPageForUser(User $user, $pageId)
{
    $qb = $this->getEntityManager()->createQueryBuilder();

    $qb->add('select', 'p')
       ->from('Application\Model\Entity\Page', 'p')
       ->join('Application\Model\Entity\TestSuite', 'ts', 'WITH', 'p.test_suite_id = ts.id')
       ->join('Application\Model\Entity\User', 'u', 'WITH', 'ts.user_id = u.id')
       ->where('p.id = :pageId')
       ->andWhere('u = :user')
       ->setParameter('user', $user)
       ->setParameter('pageId', $pageId);

    return $qb->getQuery()->getResult();
}
Run Code Online (Sandbox Code Playgroud)

请注意,我只是在这里User和在$pageId这里.由查询本身决定用户是否通过测试套件加入具有该特定页面.

如您所见,Page实体显然有一个test_suite_id指向实体id列的外键列TestSuite,我的架构反映了这一点.

生成的查询

SELECT p FROM Application\Model\Entity\Page p INNER JOIN Application\Model\Entity\TestSuite ts WITH p.test_suite_id = ts.id INNER JOIN Application\Model\Entity\User u WITH ts.user_id = u.id WHERE p. id =:pageId AND u =:user

其他帖子建议如下:

  • 清除缓存 - 我没有启用缓存层
  • 重启Apache - 它没有任何区别
  • 将"Colum"重命名为"Column" - 我不是那么愚蠢
  • 将FQDN放入targetEntity- 它们位于同一目录中,因此不需要

为什么我会特别提到这个问题,我该怎么办呢?

Ocr*_*ius 10

DQL是静态类型的,DQL语法是关于对象属性,而不是SQL列.

此外,无需直接选择关联实体:连接由DQL查询组件自动放置,并ON在结果SQL中正确生成必需的子句.

以下是您应该使用的查询版本:

SELECT
    p
FROM
    Application\Model\Entity\Page p
INNER JOIN
    p.testSuite AS ts
INNER JOIN
    ts.user u
WHERE
    p.id = :pageId
    AND u = :user
Run Code Online (Sandbox Code Playgroud)

既然Application\Model\Entity\TestSuite#$userto-one关联,您可以通过删除一个连接条件来进一步简化查询:

SELECT
    p
FROM
    Application\Model\Entity\Page p
INNER JOIN
    p.testSuite AS ts
WHERE
    p.id = :pageId
    AND ts.user = :user
Run Code Online (Sandbox Code Playgroud)

上述查询中后一个的关联DQL构建器代码如下:

public function findPageForUser(User $user, $pageId)
{
    $qb = $this->getEntityManager()->createQueryBuilder();

    $qb->add('select', 'p')
       ->from('Application\Model\Entity\Page', 'p')
       ->join('Application\Model\Entity\TestSuite', 'ts')
       ->where('p.id = :pageId')
       ->andWhere('ts.user = :user')
       ->setParameter('user', $user)
       ->setParameter('pageId', $pageId);

    return $qb->getQuery()
              ->setFetchMode("Application\Model\Entity\Page", "elements", "EAGER")
              ->getResult();
}
Run Code Online (Sandbox Code Playgroud)

  • 根据聊天中的讨论:`WITH`将用作连接的附加限制子句,或者作为对所谓的"任意连接"(两个非关联实体之间的连接)的限制.在所有情况下,DQL都不了解列名,只了解属性名. (2认同)