Doctrine 2 JOIN ON error
Asked Answered
E

3

7

I try to execute this query in my CompanyRepository

$qb = $this->_em->createQueryBuilder();
$qb->select(array('c', 'ld'))
        ->from('Model\Entity\Company', 'c')
        ->leftJoin('c.legaldetails', 'ld', \Doctrine\ORM\Query\Expr\Join::ON, 'c.companyid=ld.companyid');

$query = $qb->getQuery();
echo($query->getSQL());

When I try to do it I having error:

Fatal error: Uncaught exception 'Doctrine\ORM\Query\QueryException' with message '[Syntax Error] line 0, col 69: Error: Expected end of string, got 'ON'' in /home/raccoon/web/freetopay.dev/www/class/new/library/Doctrine/ORM/Query/QueryException.php on line 42

These are my models:

<?php    
namespace Model\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Company
 *
 * @ORM\Table(name="Company")
 * @ORM\Entity(repositoryClass="\Model\Repository\CompanyRepository")
 */
class Company
{
/**
 * @var integer $companyid
 *
 * @ORM\Column(name="CompanyID", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $companyid;

/**
 * @var \Model\Entity\LegalDetails $legaldetails
 *
 * @ORM\OneToOne(targetEntity="\Model\Entity\Legaldetails", mappedBy="companyid")
 */
private $legaldetails;

//other fields

public function __construct()
{
    $this->legaldetails = new ArrayCollection();
}    

//setters and getters

and legaldetails entity:

<?php
namespace Model\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Legaldetails
 *
 * @ORM\Table(name="LegalDetails")
 * @ORM\Entity
 */
class Legaldetails
{
/**
 * @var integer $legalid
 *
 * @ORM\Column(name="LegalID", type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
private $legalid;

/**
 * @var \Model\Entity\Company $company
 *
 * @ORM\Column(name="CompanyID", type="integer", nullable=false)
 * @ORM\OneToOne(targetEntity="\Model\Entity\Company", inversedBy="companyid")
 * @ORM\JoinColumn(name="companyid", referencedColumnName="companyid")
 */
private $company;

What is wrong?

Endocardial answered 20/1, 2012 at 9:24 Comment(0)
H
4

There's a pretty clear explanation about how JOIN's work with DQL here:

With DQL when you write a join, it can be a filtering join (similar to the concept of join in SQL used for limiting or aggregating results) or a fetch join (used to fetch related records and include them in the result of the main query). When you include fields from the joined entity in the SELECT clause you get a fetch join

this should be enough to get what you want (info about all companies with legal info loaded):

$query = $em->createQuery('SELECT c, ld FROM \Model\Entity\Company c JOIN c.legaldetails ld');
$companies = $query->getResult(); // array of Company objects with the legaldetails association loaded

EDIT:

i used a regular join in my query, so companies with no legal info won't be returned in the query. if you want ALL companies even though they have no legal info loaded you should try with the left join as you were doing

Hatpin answered 20/1, 2012 at 14:12 Comment(1)
Thanks a lot! Problem solved! I changet my entities annotation like this /** * @var Legaldetails $legaldetail * * @ORM\OneToOne(targetEntity="Legaldetails", mappedBy="company") */ private $legaldetail; in company entity and /** * @var Company $company * * @ORM\OneToOne(targetEntity="Company") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="CompanyID", referencedColumnName="CompanyID", unique=true) * }) */ private $company; in legaldetailsEndocardial
A
37

For those who came here with the question about "Expected end of string, got 'ON'", but could not find the right answer, as I couldn't (well, there is an answer, but not exactly about QueryBuilder). In general, yes, you don't need to specify the joining columns. But what if you need to add extra filtering. For example, I was looking to add an extra condition (to allow nulls in join).

The problem here is that even though the constant Join::ON exists (and comments in Join expression mention it as well), there is no ON in DQL. Instead, one should use WITH (Join::WITH).

Here is my usage example:

$qb->leftJoin('p.metadata', 'm', Join::WITH, "IFNULL(m.name, '') = 'email'");

P.S. Predicting questions about IFNULL() - it is a Benjamin Eberlei's Doctrine extension.

Antifederalist answered 20/10, 2013 at 16:12 Comment(1)
if anyone is interested the full namespace for Join::WITH is \Doctrine\ORM\Query\Expr\Join::WITHEdee
H
4

There's a pretty clear explanation about how JOIN's work with DQL here:

With DQL when you write a join, it can be a filtering join (similar to the concept of join in SQL used for limiting or aggregating results) or a fetch join (used to fetch related records and include them in the result of the main query). When you include fields from the joined entity in the SELECT clause you get a fetch join

this should be enough to get what you want (info about all companies with legal info loaded):

$query = $em->createQuery('SELECT c, ld FROM \Model\Entity\Company c JOIN c.legaldetails ld');
$companies = $query->getResult(); // array of Company objects with the legaldetails association loaded

EDIT:

i used a regular join in my query, so companies with no legal info won't be returned in the query. if you want ALL companies even though they have no legal info loaded you should try with the left join as you were doing

Hatpin answered 20/1, 2012 at 14:12 Comment(1)
Thanks a lot! Problem solved! I changet my entities annotation like this /** * @var Legaldetails $legaldetail * * @ORM\OneToOne(targetEntity="Legaldetails", mappedBy="company") */ private $legaldetail; in company entity and /** * @var Company $company * * @ORM\OneToOne(targetEntity="Company") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="CompanyID", referencedColumnName="CompanyID", unique=true) * }) */ private $company; in legaldetailsEndocardial
C
2

We both thought in terms of SQL. But in DQL WITH is used instead of ON. example

Edit: If you know SQL, why you don't use query such as:

    $query = $this->getEntityManager()->createQuery('
        SELECT t...
    ');

Put there the SQL that you think should be there, check it. If it works - the problem is in Doctrine code, if not - the error is in SQL/DQL

Cystoscope answered 20/1, 2012 at 9:31 Comment(2)
No, it isn't help. I have to use ON operator. I can't declare my :companyid variable (like WITH c.companyid = :companyid WHERE ld.companyid = :companyid) I try get information about all companies in DB with joined legal information about companyEndocardial
The problem was in entity annotations. But thank you for you help!=)Endocardial

© 2022 - 2024 — McMap. All rights reserved.