Getting entity which has some elements - php

I have a Book entity which has a One2Many relationship with the Page entity. I wanted to create a query which retrieved all the books which had at least one page. I did:
$qb = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Book')
->createQueryBuilder('b');
->leftJoin('b.pages','p')
->having($qb->expr()->gt($qb->expr()->count('p'), 0));
$books = $qb
->getQuery()
->getResult();
The problem is that, although there are many books which have pages, this query only returns a single book.
The query created is:
SELECT b FROM Acme\DemoBundle\Entity\Book b LEFT JOIN b.pages p HAVING COUNT(p) > 0
which looks fine to me. Any idea what may be wrong?

It is simpler to use
->innerJoin('b.pages','p')
instead of
->leftJoin('b.pages','p')
you don't need aggregate function. In short: this innerjoin will return only Books that can be joined with at least one Page.

You should add groupBy as you are using aggregate function. e.g.
$qb = $this->getDoctrine()
->getRepository('AcmeDemoBundle:Book')
->createQueryBuilder('b');
->leftJoin('b.pages','p')
->groupBy('b.id')
->having($qb->expr()->gt($qb->expr()->count('p'), 0));

Related

SQL select show table if not same value from another table (Laravel)

This is my query, I tried this query it works.
SELECT *
FROM conference_venue
WHERE id_venue NOT IN (SELECT id_venue FROM submission_data WHERE id_submission = 1);
i want to display data in conference_venue. but I don't want to display data whose id_venue is the same as the submission_data table (same as id_venue whose id_submission is mentioned).
I'm trying to make a query for the laravel version, but it's a blank white screen with no errors.
DB::table('conference_venue')
->whereNotIn('id_venue', function($q){
$q->select('id_venue')
->from('submission_data')
->where('id_submission', '=', 1);
})->select('*')->get();
This query works when I try it in sql query console but fails when I try it with Laravel query builder.
You can try this:
DB::table('conference_venue')
->select('*')
->whereRaw(
'conference_venue.id_venue NOT IN (SELECT submission_data.id_venue FROM submission_data WHERE id_submission = 1)'
);
Or better yet, create a Model for conference_venue and submission_data (ie: ConferenceVenue, SubmissionData) and you can add Eloquent relationships for ConferenceVenue and SubmissionData.
Eloquent relationships, which supports a variety of common
relationships (One To One, One To Many, Many To Many, etc.), are
defined as methods on your Eloquent model classes. Since relationships
also serve as powerful query builders, defining relationships as
methods provides powerful method chaining and querying capabilities.
Eloquent: Relationships
On you ConferenceVenue Class, you can add a method something similar to the following:
public function available() {
return this->hasMany(SubmissionData, 'id_venue')
->select('*') // You can also specify relevant columns ONLY
->whereRaw(
'conference_venue.id_venue NOT IN (SELECT submission_data.id_venue FROM submission_data WHERE id_submission = 1)'
);
}
Where you can use the relationship method as follows:
$available = ConferenceVenue::with('available')->get();

Expand multiple collections of an entity in Doctrine

I'm writing a Symfony application, and I am facing a problem with Doctrine entities eager loading.
I'm not sure if I can load multiple one to many collections on the same entity instance while keeping good performance.
There are many examples on the internet with people load one entity and one of its relationships.
Ex :
$user = $em->createQuery('
select a, au
from OctiviTestBundle:Article a
left join a.authorList au
where a.id = ?1')
->setParameter(1, $id)
->getOneOrNullResult();
However if I also want to load the article comments, the following request retrieves too many results (nb authors * nb comments) => combinatory explosion
$user = $em->createQuery('
select a, au
from OctiviTestBundle:Article a
left join a.authorList au
left join a.commentList c
where a.id = ?1')
->setParameter(1, $id)
->getOneOrNullResult();
In fact, I found no way to reuse an object once it has been loaded from the database. I don't know how to make a second query to load more parts of it later.
Eg :
$user = $em->createQuery('
select a, au
from OctiviTestBundle:Article a
left join a.authorList au
where a.id = ?1')
->setParameter(1, $id)
->getOneOrNullResult();
$em->LoadRelation($user, 'commentList');
$em->LoadRelation($user, 'commentList.author')
$em->LoadRelation($user, 'commentList.author.school');
... load any relation I want, while keeping only one root object.
I would like to be able to have only the main entity instance variable, eager load its 2 relationships and then go through the hierarchy.
I know I can load the two lists in different php variables, but I'd like to only pass the "$user" variable to the view template.
Do you have ideas about how to resolve this issue ?
Thanks
The only (tricky) solution I found is on this website : https://tideways.io/profiler/blog/5-doctrine-orm-performance-traps-you-should-avoid
1) Load the related entities
$companies = array_map(function($employee) {
return $employee->getCompany();
}, $employees);
$repository = $entityManager->getRepository('Acme\Company');
$repository->findBy(['id' => $companies]);
2) Don't use the result (drop the $companies variable), but now Doctrine has got the results in cache, so when I do $employee->getCompany()->getName(), it should not generate new queries.
=> Doesn't work : Doctrine doesn't put the results in the cache to reuse them later.
If the result is always going to be massive no matter what where's and ands you put in, and if you have no intent on doing any write operations on the result you should fetch them as an array instead of as the default objects.
The resulting array is still used exactly the same within twig however as you no longer have to hydrate the objects your memory saving will be huge.

Issue with "where" in an associated query in Symfony 3

I'm trying to make a "search engine" for my app; the table I want to show, contains two fields which are associated to another tables.
I'm using this query:
Select work from WorkBundle:Work work
where work.client.name like '$search%'
Work, is associated with the tables "user" and "client", I have the associations correctly defined so I don't have to use the inner join statement, but I get the following error:
[Semantical Error] line 0, col 68 near 'nombre like 'fsdf%'': Error: Class WorkBundle\Entity\Work has no field or association named client.nombre
I don't know how to access to the "name" field which is on the "client" table.
Actually I can do the same by using a full inner join query and it works but I can't use it in my app.
I do not know for sure but it seems you cant use selectors like work.client.name. I think it based on doctrine uses "lazy" queries. So you must use table joins in this case.
So it should look smth like that
// work repository
public function findByKeyword($keyword)
{
$qb = $this->createQueryBuilder("w");
$result = $qb
->add('where', $qb->expr()->like("wc.name", ':keyword'))
->leftjoin("w.client", "wc") //or join or innerjoin depends of your case
->setParameters([
'keyword' => $keyword
])
->getQuery()
->getResult()
;
return $result;
}

How to get multi activerecord model with only 1 join query in Yii2?

For example:
Query
SELECT book.\*,author.* FROM book
INNER JOIN author ON author.id = book.author_id
WHERE book.id=1
Get model
$modelBook = Book::find()->innerJoin('author','author.id = book.author_id')->where(['book.id'=>1])->one();
$modelAuthor = Author::findOne(['id'=>$modelBook->author_id]);
The problem:
How can I get 2 activerecord model Book and Author with just only one mysql execute?
I know that we can use with() function, but it spend another query SELECT ...IN(...) to get second model, although we have sufficient data from join query
Is there a more effective solution ?
ActiveRecord are for model extendinng the ActiveRecord classe
You seems are using a query and not a "model" so i suggest you of use activeDataProvider.
You can refer the models managed by dataProvider using getModels() function
$provider = new SqlDataProvider([
......
]);
// returns an array of data rows
$models = $provider->getModels();
see this guide and reference for detail
http://www.yiiframework.com/doc-2.0/guide-output-data-providers.html
http://www.yiiframework.com/doc-2.0/yii-data-sqldataprovider.html
Try this :
With approach is not slower in case of performance.
$modelBook = Book::find()->with('YOUR_RELATION_NAME_HERE')->findByPK(id);

Symfony2 - Custom Query in Entity Repo doesn't seem to return expected results

So I came to a point where I needed to create a custom query in my Entity Repository to do a sub-select.
The query itself seems sound and does indeed find the result I am after (I checked by running the query in Navicat) however, when trying to view the results (using Twig templates) I am getting the following error:
Item "id" for "Array" does not exist in DEMODemoBundle:Staff/Company:company.html.twig at line 42
Line 42 in that template is:
<td>{{ entity.id }}</td>
Previously, I was using a basic "findAll" query in my controller, and the Twig template worked fine (it uses a for loop to go through the results and print out a table)
So, I was under the assumption that if my custom query fetched a list of results, with all the same columns (just 1 added extra in the sub-select, not the ID mentioned though) then everything should be fine!
But clearly not. It seems as though there is another Array level for some reason and I am unsure as to why?
Here is my custom query in the repo (it does a sub select to create a parent_name column):
public function getCompanyWithParent()
{
$dql = 'SELECT c, (SELECT p.name FROM DEMO\DemoBundle\Entity\User\Company p WHERE p.id = c.parent) as parent_name FROM DEMO\DemoBundle\Entity\User\Company c';
$query = $this->getEntityManager()->createQuery($dql);
return $query->getArrayResult();
}
I have tried both:
return $query->getArrayResult();
and
return $query->getResult();
But to no avail.
Any ideas folks?
Sorted it. Seems I had to specify the columns I wanted to pull through e.g. SELECT c.id, c.name ..., and sadly couldn't just use SELECT c, ... FROM ...

Categories