I have query with two MtM relations:
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$qb
->select('o')
->from('UserBundle:User', 'o')
;
$qb->join('o.organisations', 'org')
->where('org.id = :organisation')
->setParameter('organisation', $filterData['organisation'])
;
$qb
->join('o.scientificDirections', 'd')
->where('d.id IN (:directionIds)')
->setParameter('directionIds', $directionIds)
->orderBy('o.surname')
;
return $qb->getQuery();
But it gives me error: Invalid parameter number: number of bound variables does not match number of tokens.
Can anybody explain me what is wrong?
Relation in User model:
/**
* #ORM\ManyToMany(targetEntity="\StrangeBundle\Entity\ScientificDirection")
*
*/
protected $scientificDirections;
/**
* #ORM\ManyToMany(targetEntity="\StrangeBundle\Entity\Organisation", mappedBy="workers")
*/
protected $organisations;
I think the reason is because you used where twice. That overwrites the first where, which is why it is giving you the parameters number error.
Use andWhere
Related
I have 2 entities :
LinkServInfra
Serv
LinkServInfra entity :
id
serv (relation OneToOne to Serv)
infra (ManyToOne to another entity)
Now, I'd like to get a list of Serv based on infra.
So I tried in LinkServInfraRepository :
$qb = $this->createQueryBuilder('s')
->select('DISTINCT s.serv')
->where('s.infra = :infra')
->setParameter('infra', $infra);
return $qb->getQuery()->getResult();
And I get an error :
[Semantical Error] near 'serv FROM': Error: InvalidPathExpression.
Must be a StateFieldPathExpression.
(I tried first without DISTINCT and tried with it based on answer found here).
The query seems to be good because it's :
SELECT DISTINCT s.serv
FROM MyBundle\Entity\LinkServInfra s
WHERE s.infra = :infra
How would you do?
Thanks!
Since the relation is ONLY in LinkServInfra and not in Serv :
I used the relation in LinkServInfra to do it...
public function filter($type, $etat, $infra){
$qb = $this->createQueryBuilder('l');
$qb->where(' l.infra = :infra ')
->setParameter('infra', $infra);
if( $type || $etat ){
$qb->join('l.serv', 's')
//where & setParameter for type
//where & setParameter for detail
}
And then where I call the function filter :
$entities = $em->getRepository('linkServInfra')->filter(//...
$servs = array();
foreach($entities as $entity){
$servs[] = $entity->getServ();
}
I guess it's not the cleanest solution but it's working...
I think you can not use DISTINCT on a relation, only for the root entity alias.
You should use Serv entity as root and join with LinkServInfra and infra entity through the 2nd. Something like:
$qb = $this->getDoctrine()
->getRepository(Serv::class)->createQueryBuilder('s')
->select('DISTINCT s')
->leftJoin("s.linkServInfra", "lsi")
->leftJoin("lsi.infra", "infra")
->where('infra.id = :infra')
->setParameter('infra', 1);
Alternatively, if the relation is unidirectional and you do not want to make it bidirectional, you can use a custom join:
use Doctrine\ORM\Query\Expr\Join;
$qb = $this->getDoctrine()
->getRepository(Serv::class)->createQueryBuilder('s')
->select('DISTINCT s')
->leftJoin(LinkServInfra::class, "lsi", Join::WITH, 'lsi.serv = s')
->leftJoin("lsi.infra", "infra")
->where('infra.id = :infra')
->setParameter('infra', 1);
References
How to JOIN without a relationship in Doctrine?
I wrote this query.
$query = $this->getEntityManager()->createQueryBuilder();
$query->select(['cart','subscriptions', 'member'])
->from('ComitiUserBundle:Cart', 'cart')
->leftJoin('cart.subscriptions', 'subscriptions')
->leftJoin('subscriptions.member', 'member')
->where('cart.club = :club_id')
->andWhere('subscriptions.clubSeason = :season_id')
->setParameter('club_id', $club)
->setParameter('season_id', $season);
if($section != null && !is_array($section)){
$query->andWhere('subscriptions.section = :section_id')
->setParameter('section_id', $section);
} elseif($section != null && is_array($section)){
$query->andWhere('subscriptions.section IN :section_ids')
->setParameter('section_ids', $section);
}
$query->orderBy('cart.transaction_date','DESC');
return $query->getQuery()->getResult();
I've got this error in return :
[Syntax Error] line 0, col 28: Error: Expected IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression, got 'member'
In fact I try to hydrate my result collection with members in it. Member is manyToOne property in my Subscription entity. It is defined like this :
/**
* #ORM\ManyToOne(targetEntity="Comiti\UserBundle\Entity\UserComiti", inversedBy="subscriptions", cascade={"persist"})
* #ORM\JoinColumn(name="member_id", referencedColumnName="id")
*/
protected $member;
So I ran into the exact same error when trying to join a category group for a category entity. See the code below:
$qb = $this->entityManager->createQueryBuilder()
->select('c')
->from(Category::class, 'c');
if (isset($fields['categoryGroup'])) {
$qb = $qb->join('c.categoryGroup', 'group')
->addSelect('group');
}
$qb = $qb->getQuery()
->getArrayResult();
This resulted in the exact same error as the OP, only with 'group'. My guess is that you cannot use database reserved words in the query, like group and member.
For me, changing the alias to something like cg worked just fine.
Goal: Ordering my entities on how ofter they are used on associated relations (oneToMany)
The problem: DQL, it somehow handles the FROM keyword is an entity or class.
The Exception thrown: QueryException: [Semantical Error] line 0 col 103 near 'FROM MyBundle:Entity Error: Class 'FROM' is not defined.
Here is a SQL query I wrote to test how to get the data. It works perfectly
SELECT en.id, (COUNT(DISTINCT ag.artist_id) + COUNT(DISTINCT rg.release_id) + COUNT(DISTINCT tg.track_id)) AS total
FROM myapp.entity AS en
LEFT JOIN myapp.other_one AS o1 ON o1.entity_id = en.id
LEFT JOIN myapp.other_two AS o2 ON o2.entity_id = en.id
GROUP BY en.id
ORDER BY total DESC ;
To get the data in symfony to hydrate to objects I try to use Doctrine Query Language in the EntityRepository like this:
/**
* Find Most Common Entities
*
* #return array
*/
public function findMostCommon()
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$qb
->select('en, (COUNT(DISTINCT en.other1) + COUNT(DISTINCT en.other2)) AS count')
->from('MarulaBundle:Entity', 'en')
->leftJoin('MyBundle:Other1', 'o1', 'WITH', 'o1.entity = en.id')
->leftJoin('MyBundle:Other2', 'o2', 'WITH', 'o2.entity = en.id')
->groupBy('en')
->orderBy('count', 'DESC')
;
return $qb->getQuery()->getResult();
}
Since it is possible in a SQL query. I was hoping it would work just as fine with DQL.
Has anyone experienced this error before? Is it even possible to achieve this with Doctrine, or is doctrine limited relating this issue?
OOPS: I should not use the keyword "count"
Solution:
->select('en, (COUNT(DISTINCT en.other1) + COUNT(DISTINCT en.other2)) AS HIDDEN orderCount')
note: adding the HIDDEN keyword helps to get only the entities back, which makes the hydration fit right in
I have an issue to find an alternative way to count Users who suffer a pathology (a count with a group by)
the issue is I prefer not to make a for loop on pathologies to count that, and I'de like if I could get your advice.
here's some pieces of code I have :
User Entity :
/**
* #ORM\OneToMany(targetEntity="Hospitalisation", mappedBy="user")
*/
private $hospitalisations;
Hospitalisation Entity:
/**
* #ORM\ManyToOne(targetEntity="Pathologie", inversedBy="hospitalisations")
*/
private $pathologie;
Pathology Entity:
/**
* #ORM\OneToMany(targetEntity="Hospitalisation", mappedBy="pathologie")
*/
private $hospitalisations;
What I have to do is to count how many users suffers of each pathologie in the database.
Thank you :)
Create a custom repository class PathologieRepository
http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes
Add this (not tested):
public function countUsers($pathologieID)
{
$result = $this->getEntityManager()
->createQuery("
SELECT COUNT(u) as c FROM YourMainBundle:Users u
JOIN u.hospitalisations h
JOIN h.pathologies p
WHERE
p.id = :pathologie
")
->setParameter('pathologie', $pathologieID)
->setMaxResults(1)
->getSingleResult();
return $result['c'];
}
If you want do this in twig like (pseudo):
for pathologie as p
print p.countUsers(p.id)
You have to create a method in your pathologie entity class. But you cannot use entity manager in entity classes (you can by using a hack but this is not recommended). So you have to use loops to count the users.
public function getUserCount()
{
$hospitalisations = $this->getHospitalisations();
$counter = 0;
foreach ($hospitalisations as $h)
{
$counter += count($h->getUsers());
}
return $counter;
}
I solved the issue.
Here's the solution i've come up with:
$result = $this->getEntityManager()
->createQuery("
SELECT p.id, p.nom, COUNT(DISTINCT u) as nbUsers , COUNT(DISTINCT i) as nbImported
FROM AcmeDemoBundlePathologie p
left JOIN p.importedUsers i
left JOIN p.hospitalisations h
left JOIN h.user u
GROUP BY p.id, p.nom
")
->getArrayResult();
I have an entity named 'tile', with a manyToMany relationship with another entity named 'coins'.
/**
* #ORM\ManyToMany(targetEntity="Coin")
* #ORM\JoinTable(name="coin",
* joinColumns={#ORM\JoinColumn(name="tile_id", referencedColumnName="tile_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="coin_id", referencedColumnName="coin_id")}
* )
**/
protected $coins;
I have a page that lists tiles and all of their associated coins. There can be a lot of coins and tiles on a page and using lazy loading can put 100-300 database queries on a single page. I am trying to avoid this by using a leftJoin.
public function getUserTiles($id)
{
$qb = $this->createQueryBuilder('b')
->select('b', 'z')
->leftJoin('b.coins', 'z')
->leftJoin('z.userInfo', 'u')
->add('where', "b.userId = ".$id." AND b.status = 'COMPLETED'")
->add('orderBy', "b.checkinDate DESC");
return $qb->getQuery()
->getResult();
}
This gives me the following error:
*[2/2] DBALException: An exception occurred while executing '
SELECT t0_.tile_id AS tile_id0, t0_.quilt_id AS quilt_id1, t0_.user_id AS user_id2, t0_.comment AS comment3, t0_.checkout_date AS checkout_date4, t0_.checkin_date AS checkin_date5, t0_.x AS x6, t0_.y AS y7, t0_.status AS status8, t0_.completed_neighbors AS completed_neighbors9, t0_.required_completed_neighbors AS required_completed_neighbors10, t0_.visible AS visible11, t0_.visible_date AS visible_date12, t0_.count_towards_coins AS count_towards_coins13, c1_.coin_id AS coin_id14, c1_.user_id AS user_id15, c1_.tile_id AS tile_id16, c1_.comment AS comment17, c1_.date_given AS date_given18, c1_.status AS status19, c1_.origin AS origin20, t0_.quilt_id AS quilt_id21, t0_.user_id AS user_id22, c1_.tile_id AS tile_id23, c1_.user_id AS user_id24
FROM tile t0_ **LEFT JOIN coin *c1_* ON t0_.tile_id = c1_.tile_id
LEFT JOIN coin *c1_* ON c1_.coin_id = c1_.coin_id**
LEFT JOIN user_info u2_ ON c1_.user_id = u2_.user_id
WHERE t0_.user_id = 14 AND t0_.status = 'COMPLETED'
ORDER BY t0_.checkin_date DESC':
SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'c1_'*
As you can see, it is trying to join the coin table twice, using the same alias. What am I doing wrong?
Try:
$this->createQueryBuilder('b')
->select('b')
->addSelect('z')
->leftJoin('b.coins', 'z')
->leftJoin('z.userInfo', 'u')
->where("b.userId = :id AND b.status = 'COMPLETED'")
->orderBy('b.checkinDate', 'DESC')
->setParameter('id', $id)
->getQuery('b.checkinDate DESC')
->getSingleResult();
I fixed this problem by changing the ManyToMany relationship to OneToMany as it should have been in the first place.