Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an ORM adapter which allows fetch joins #121

Merged
merged 1 commit into from
Apr 29, 2020

Conversation

jbtronics
Copy link
Contributor

@jbtronics jbtronics commented Jan 17, 2020

The default ORM adapter does not allow queries where doctrine performs fetch joins (selecting additional entities via joins), because the normal result limit statements do not work there (it causes strange bugs like pages with only one row).

However doctrine offers the Pagiator class which can correctly determine page counts and elements for each page.

I wrote an adapter using doctrine paginator (extending the basic ORMAdapter) and because using fetch joins in more complex queries (to avoid the N+1 query problem) , I propose this adapter for the main repository.

I think a separate adapter is reasonable for this case, because the FetchJoinAdapter is slower than the normal adapter (because it have to perform 3 queries to determine the correct results) and it only supports object hydration mode, so a developer should explicitly choose to use this adapter.

This PR should also solve issue #93 .

@curry684 curry684 requested a review from shades684 February 10, 2020 11:34
@rwkt
Copy link
Contributor

rwkt commented Feb 23, 2020

Are you able to post a basic example of it's usage? I've been trying to get this to work with the code below but I'm not having any luck; this is for a OneToMany relation (one customer has many phones - but only display one phone as the main one).

$table = $dataTableFactory->create()
	->add('mainPhone', TextColumn::class, ['field' => 'p.value'])
	->createAdapter(FetchJoinORMAdapter::class, [
		'entity' => Customer::class,
		'query' => function (QueryBuilder $builder) {
			$builder
				->distinct()
				->select('c, p')
				->from(Customer::class, 'c')
				->leftJoin('c.phones', 'p', 'WITH', 'p.isMain = 1 AND p.category = 0')
				;
		},
	])
	->handleRequest($request);
**App\Entity\Customer**
     /**
     * @ORM\OneToMany(targetEntity="App\Entity\Phone", mappedBy="customer", cascade={"persist"})
     */
    private $phones;

@jbtronics
Copy link
Contributor Author

Are you able to post a basic example of it's usage? I've been trying to get this to work with the code below but I'm not having any luck; this is for a OneToMany relation (one customer has many phones - but only display one phone as the main one).

The adapter just allow to fetch multiple objects at once. If you want to show it somehow, you have to implement your own logic, that transform the objects somehow to a field. (Maybe it would be possible to add a new column for that).

Taking your example code above, you would change the TextColoumnLine to something like this:
->add('mainPhone', TextColumn::class, [ 'render' => 'render' => function ($value, $context) { $str = ''; foreach ($context->getPhones() as $phone) { $str .= $phone->getName() . '\n'; } return $str; } ]);

As the phones objects are already populated with data, this will not cause any more database queries (unlike when using the default ORMAdapter).

Copy link
Contributor

@shades684 shades684 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@curry684 basically he and i did the same thing by making those private members protected. We had a long discussion why it was a bad idea.

From a pure perspective it's bad practice.
From a practical perspective I've heard this same problem one to many times and this is a valid way to fix it.

@curry684 curry684 merged commit ed00d89 into omines:master Apr 29, 2020
@curry684
Copy link
Member

OK :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants