i'm trying to convert a query to DQL or build ir with query builder.
I can retrive with success the results from database with the following query:
SELECT * FROM flag
left join countries
on flag.id = countries.flag
where countries.flag IS NULL
Now, i need to conver this to DQL or build it with queryBuilder.
My entities are Country and Flag. The entity Country as a field flag as a external id.
So far, i got the following code:
$qb = $em->createQueryBuilder();
$available =
$qb
->select('f')
->from('Flag', 'f')
->leftJoin('Countries', 'c', 'ON', 'c.flag = f.id')
->where('f.id IS NULL');
My dump of $available doesnt return anything.
What's whong with this QueryBuilder?
Thanks.
you also need to actually execute the query:
$result = $qb->getQuery()->execute();
that should give you the results.
where('f.id IS NULL');
is wrong.
It should be
where('c.flag IS NULL');
Thanks for the help.
Both answers are correct. Heres the final code, in case someone else search.
Also, i had to replace the 'ON' with 'WITH'.
$available =
$qb
->select('f')
->from('Flag', 'f')
->leftJoin('Countries', 'c', 'WITH', 'c.flag = f.id')
->where('c.flag IS NULL');
$flags = $qb->getQuery()->execute();
Related
I have some One-To-Many, unidirectional with Join Table relationships in a Symfony App which I need to query and I can't figure out how to do that in DQL or Query Builder.
The Like entity doesn't have a comments property itself because it can be owned by a lot of different types of entities.
Basically I would need to translate something like this:
SELECT likes
FROM AppBundle:Standard\Like likes
INNER JOIN comment_like ON comment_like.like_id = likes.id
INNER JOIN comments ON comment_like.comment_id = comments.id
WHERE likes.created_by = :user_id
AND likes.active = 1
AND comments.id = :comment_id
I've already tried this but the join output is incorrect, it selects any active Like regardless of its association with the given comment
$this->createQueryBuilder('l')
->select('l')
->innerJoin('AppBundle:Standard\Comment', 'c')
->where('l.owner = :user')
->andWhere('c = :comment')
->andWhere('l.active = 1')
->setParameter('user', $user)
->setParameter('comment', $comment)
I see 2 options to resolve this:
Make relation bi-directional
Use SQL (native query) + ResultSetMapping.
For the last option, here is example of repository method (just checked that it works):
public function getLikes(Comment $comment, $user)
{
$sql = '
SELECT l.id, l.active, l.owner
FROM `like` l
INNER JOIN comment_like ON l.id = comment_like.like_id
WHERE comment_like.comment_id = :comment_id
AND l.active = 1
AND l.owner = :user_id
';
$rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->_em);
$rsm->addRootEntityFromClassMetadata(Like::class, 'l');
return $this->_em->createNativeQuery($sql, $rsm)
->setParameter('comment_id', $comment->getId())
->setParameter('user_id', $user)
->getResult();
}
PS: In case of Mysql, 'like' is reserved word. So, if one wants to have table with name 'like' - just surround name with backticks on definition:
* #ORM\Table(name="`like`")
I find the Symfony documentation very poor about unidirectional queries.
Anyway I got it working by using DQL and sub-select on the owning entity, which is certainly not as fast. Any suggestion on how to improve that is more than welcomed!
$em = $this->getEntityManager();
$query = $em->createQuery('
SELECT l
FROM AppBundle:Standard\Like l
WHERE l.id IN (
SELECT l2.id
FROM AppBundle:Standard\Comment c
JOIN c.likes l2
WHERE c = :comment
AND l2.owner = :user
AND l2.active = 1
)'
)
->setParameter('user', $user)
->setParameter('comment', $comment)
;
I’m using QueryBuilder in the in the following way:
$qb = $entityManager->createQueryBuilder();
$qb->select('m')
->from('MyEntity', 'm');
$query = $qb->getQuery();
$collection = $query->getResult();
foreach ($collection as $item) {
$qb = $entityManager->createQueryBuilder();
$qb->update('MyEntity ', 'm')
->set('m.myItem', '?1');
$query = $qb->getQuery();
$result = $query->execute();
}
(I've remove a lot of details in order to focus on the gist of the question)
How should this script be written?
Is it appropriate to reuse $qb or should I use $qb1, $qb2,
etc.?
In this particular script, the results of the first instance of
QueryBuilder get passed into an array $collection before the next
steps, so I assume that I’m done with the first instance of
QueryBuilder at that time. Does there need to be something like
$qb->close before moving on?
Is it necessary to say $qb = $entityManager->createQueryBuilder();
more than once?
I have query
$Select = 'SELECT COUNT(o.Id) FROM Entities\Order o';
How to rewrite this query for query builder?
$qb = $this->entityManager->createQueryBuilder();
$qb->select(.....
Thanks
It is very straight forward as you can see in the documentation.
$qb = $this->entityManager->createQueryBuilder();
$result = $qb->select('COUNT(o.Id)')
->from('Entities\Order', 'o')
->getQuery()
->getResult();
If you just want to have the number in $result you can use
$qb = $this->entityManager->createQueryBuilder();
$result = $qb->select('COUNT(o.Id)')
->from('Entities\Order', 'o')
->getQuery()
->getSingleScalarResult();
Short and Simple: From time to time we send gifts to some of our users. I have a user table and a gift table with a many-to-many relationship. I want to fetch all users which did NOT receive a particular gift.
The following query however returns me all users and the gifts they've received, with the particular gift excluded.
$qb = $this->_em->createQueryBuilder();
$qb->select('u, g')
->from('Application\Entity\User', 'u')
->leftJoin('u.gifts', 'g')
->where('g.id != = :giftId')
->setParameter('giftId', 2);
If a user received a particular gift, I want to exclude that user from the result set. Is this possible with Doctrine2?
You first need to select all users, then exclude those who had your gift already:
SELECT
u
FROM
Application\Entity\User u
WHERE
u.id NOT IN(
SELECT
u2.id
FROM
Application\Entity\User u2
JOIN
u2.gifts g
WHERE
g.id = :giftId
)
In QueryBuilder API, it looks like following:
$qb1 = $em->createQueryBuilder();
$qb2 = $em->createQueryBuilder();
$qb2
->select('u2')
->from('Application\Entity\User', 'u2')
->join('u2.gifts', 'g')
->andWhere($qb2->expr()->eq('g.id', ':giftId');
$users = $qb1
->select('u')
->from('Application\Entity\User', 'u')
->andWhere($qb1->expr->in($qb2->getDQL())
->setParameter('giftId', $giftId)
->getQuery()
->getResult();
Also, I don't personally think the QueryBuilder is suited for this use case unless you have dynamic DQL. As you can see, the query gets quite complex, and at some point you're even falling back to QueryBuilder#getDQL, which builds the DQL string and makes recycling of $qb2 impossible.
Plain DQL works just fine here.
I'm trying to order the results of my query by whether or not they match my original entity on a property. I could do this easily in mySQL with the following query:
SELECT * FROM table
ORDER BY prop = 'value' DESC;
However, in Doctrine, when I attempt the following:
// $qb is an instance of query builder
$qb->select('e')
->from('Entity', 'e')
->orderBy('e.prop = :value', 'DESC')
->setParameter('value', 'value');
// grab values
I get a Doctrine syntax error, 'end of string'. I looked into creating a custom function, but that seems like overkill. I'm fairly new to Doctrine, is there a better way to do this?
Since Doctrine ORM 2.2, you can use the HIDDEN keyword and select additional fields, in this case with a CASE expression:
SELECT
e,
CASE WHEN e.prop = :value THEN 1 ELSE 0 END AS HIDDEN sortCondition
FROM
Entity e
ORDER BY
sortCondition DESC
As I struggeled a while to figure out how to create that query using php syntax here's what I came up with:
$value = 'my-value';
$qb->select('e')
->from('Entity', 'e')
->addSelect('CASE WHEN e.prop = :value THEN 1 ELSE 0 END AS HIDDEN sortCondition')
->setParameter('value', $value)
->addOrderBy('sortCondition', 'DESC');