2

I'm new to Symfony and am trying to do a basic left join to pull in a clients name based on an client_id in the Jobs table.

App\Entity\Jobs:

class Jobs
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\ManyToOne(targetEntity="App\Entity\Clients", inversedBy="jobs")
     * @ORM\JoinColumn(nullable=false)
     */
    private $client;

Should join to App\Entity\Clients:

class Clients
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\OneToMany(targetEntity="App\Entity\Jobs", mappedBy="client")
     */
    private $jobs;

In my App\Repository\JobsRepository class, the following function is attempting the left join:

use App\Entity\Jobs;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;

class JobsRepository extends ServiceEntityRepository
{
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, Jobs::class);
    }

    public function allWithClientName()
    {
        return $this->createQueryBuilder('job')
                ->leftJoin('job.client_id', 'client')
                ->getQuery()
                ->execute();
    }
}

The error I'm getting returned is:

[Semantical Error] line 0, col 60 near 'client': Error: Class App\Entity\Jobs has no association named client_id

Any ideas? As far as my limited understanding goes, the annotations should form the required join.

k0pernikus
  • 60,309
  • 67
  • 216
  • 347
DevLime
  • 937
  • 2
  • 9
  • 19
  • @k0pernikus Yeah. After solving the problem it appears to be a duplicate of: [https://stackoverflow.com/questions/6899335/doctrine-class-has-no-association-named](https://stackoverflow.com/questions/6899335/doctrine-class-has-no-association-named) How do you mark this up as such? – DevLime May 19 '18 at 07:42
  • 1
    You can vote to close it and mark it as a Duplicate there. Then it's up to the community to close it or leave it open. You as OP have the option to accept vote to close as "Yes, this solved my problem" and it will take precedence over the community vote. – k0pernikus May 22 '18 at 09:42
  • 1
    Great. All sorted. Thanks for that :) – DevLime May 22 '18 at 09:59
  • You are welcome :) – k0pernikus May 22 '18 at 10:07

3 Answers3

1

I don't see any call to get the entityManager.

You either, forgot to call getRepository() before createQueryBuilder() or forgot to add from in your query.

Avoid to use alias that could be mistaken for entity names

Use double quote to surround your query. Because you will have an error when you will happen to write something like where('e.param="string"') as double quote isn't allowed for string in DQL.

Change $client_id to $client. Going by how doctrine does things, if left as is, you will have client_id_idas SQL column when updating schema.

Avoid plurals entities... Donctrine don't like them... ;)

Here is a full code correction

Jobs

class Jobs {
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Clients", inversedBy="id")
     * @ORM\JoinColumn(nullable=false)
     */
    private $client;
}

Client

class Clients {
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     *@ORM\OneToMany(targetEntity="App\Entity\Jobs", mappedBy="client")
     */
    private $jobs
}

JobsRepository Solution 1

use App\Entity\Jobs

class JobsRepository extends \Doctrine\ORM\EntityRepository {
    public function repoQuery() {
        $em=$this->getEntityManager();

        return $em->getRepository(Jobs::class)
                  ->createQueryBuilder("j")
                  ->leftJoin("j.client", "c")
                  ->getQuery()
                  ->execute();
    }
}

JobsRepository Solution 2

use App\Entity\Jobs

class JobsRepository extends \Doctrine\ORM\EntityRepository {
    public function repoQuery() {
        $em=$this->getEntityManager();

        return $em->createQueryBuilder()
                  ->from(Jobs::class, "j")
                  ->leftJoin("j.client", "c")
                  ->getQuery()
                  ->execute();
    }
}
Preciel
  • 2,666
  • 3
  • 20
  • 45
  • @Liam Updated my answer, you had some errors, should works as I did it... Don't forget to update schema... ;) – Preciel May 18 '18 at 09:00
  • Ah! My class JobsRepository class is already extending Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository will this likely cause a problem if I switch it out? – DevLime May 18 '18 at 09:40
  • @Liam Doctrine should handle the id just fine... As to your extends, I'm not sure what to do with it. I never chenged the extends of my repository, and it might be particular to Symfony4 (I'm using 3.4 for LTS). Anyway, it should have helped you correct some parts already... ;) – Preciel May 18 '18 at 10:07
  • Could you update your code in your question please?! (add a note saying you updated) – Preciel May 18 '18 at 15:20
  • (not high enough rank to start chat..) I've updated my answer. All seems to be working now. It was several problems in the annotations being set up wrong. Check [my answer](https://stackoverflow.com/a/50413476/9810518) below. Thanks for the assist! – DevLime May 19 '18 at 07:39
1

The below code changes resolved it for me. It appears that

  • the annotations required are @ORM\Entity on the class itself, pointing at the repository class
  • for the property the join annotation is the only one required (@ORM\ManyToOne)

As per Preciels comment, the @ORM\Entity(repositoryClass=?) annotation at the top of the class is incredibly important.

Working code

App\Entity\Jobs:

/**
 * @ORM\Entity(repositoryClass="App\Repository\JobsRepository")
 */
class Jobs
{

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Clients", inversedBy="client")
     */
    private $client;

App\Entity\Clients:

/**
 * @ORM\Entity(repositoryClass="App\Repository\ClientsRepository")
 */
class Clients
{

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Jobs", mappedBy="client", cascade={"persist", "remove"})
     */
    private $client;

App\Repository\JobsRepository:

/**
 * @return array
 */
public function allWithClientName() {


    return $this->createQueryBuilder('j')
                ->select('j as job', 'c.name as client')
                ->leftJoin('j.client', 'c')
                ->getQuery()
                ->execute();


}
DevLime
  • 937
  • 2
  • 9
  • 19
  • Oh... You you didn't set your entity annotation... couldn't notice this as it wasn't in your code examples... don't you generate entities with doctrine? It should add them by default – Preciel May 19 '18 at 21:53
  • Not before. Since I followed the online guide, I use the CLI tool now :) – DevLime May 20 '18 at 14:52
0
use Doctrine\Common\Collections\ArrayCollection;
////////////////////////////////////////////////////

class Clients
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @ORM\OneToMany(targetEntity="App\Entity\Jobs", mappedBy="client_id")
     */
    private $jobs; // Here change your $id -> to $jobs 

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

In your Repository:

public function allWithClientName()
{
    return $this->createQueryBuilder('job')
                ->leftJoin('job.client_id', 'my_client')
                ->addSelect('my_client') 
                ->getQuery()
                ->execute();
}
Imanali Mamadiev
  • 2,604
  • 2
  • 15
  • 23
  • This didn't work either. Same error but with a different alias. [Semantical Error] line 0, col 71 near 'my_client': Error: Class App\Entity\Jobs has no association named client_id. The problem appears to be with the association itself, not the query. – DevLime May 18 '18 at 08:47
  • imanali, why do you add a construct to change `jobs` as array? It's not even specified into the code examples... Also, you don't define a type and a generated value for relations... – Preciel May 18 '18 at 09:04