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

FIX Use ORM functions to perform eager loading instead of raw query #11509

Open
wants to merge 1 commit into
base: 5.3
Choose a base branch
from

Conversation

Kevinn1109
Copy link

Description

The original query was a hardcoded and a rather hacky way of retaining the ordering of the child objects while fetching from a many_many table. The method used to retain this order was 'FIELD', which is a MySQL exclusive feature and breaks in other sql engines. This change converts the query to properly make use of the ORM functions and use the ordering used in the original query directly.

Manual testing steps

  1. Create and populate two DataObjects that have a many_many relation between them
  2. Perform an eagerLoad on DataObject::get() and convert the result to an array
  3. Observe that the new SQLSelect query is performed correctly
  4. Observe that grabbing the first relation entry from the first array object is the expected DataObject and does not perform another query

Issues

Pull request checklist

  • The target branch is correct
  • All commits are relevant to the purpose of the PR (e.g. no debug statements, unrelated refactoring, or arbitrary linting)
    • Small amounts of additional linting are usually okay, but if it makes it hard to concentrate on the relevant changes, ask for the unrelated changes to be reverted, and submitted as a separate PR.
  • The commit messages follow our commit message guidelines
  • The PR follows our contribution guidelines
  • Code changes follow our coding conventions
  • This change is covered with tests (or tests aren't necessary for this change)
  • Any relevant User Help/Developer documentation is updated; for impactful changes, information is added to the changelog for the intended release
  • CI is green

. ' ORDER BY FIELD(' . $childIDField . ', ' . $fetchedIDsAsString . ')'
);
$joinRows = SQLSelect::create()
->setSelect('"' . $joinTable . '".' . "*")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
->setSelect('"' . $joinTable . '".' . "*")

It will select everything by default, I believe.

Copy link
Author

Choose a reason for hiding this comment

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

Removing the table-specific select may lead to ambiguity with the columns from the joined table. This ensures that we're always working with the correct values.

);
$joinRows = SQLSelect::create()
->setSelect('"' . $joinTable . '".' . "*")
->setFrom([$joinTable => $joinTable])
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
->setFrom([$joinTable => $joinTable])
->setFrom('"' . $joinTable . '"')

There's no need to set an alias or use an array, but we do need to escape the table name.

Comment on lines 1372 to 1373
->addWhere('"' . $parentIDField . '" IN (' . implode(',', $parentIDs) . ')')
->addWhere('"' . $childIDField . '" IN (' . $fetchedIDsAsString . ')')
Copy link
Member

Choose a reason for hiding this comment

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

You need to include the table name in addWhere so there's no ambiguity if we change the query in the future.

->setFrom([$joinTable => $joinTable])
->addWhere('"' . $parentIDField . '" IN (' . implode(',', $parentIDs) . ')')
->addWhere('"' . $childIDField . '" IN (' . $fetchedIDsAsString . ')')
->addLeftJoin($childTable, "$childTable.ID = $joinTable.$childIDField")
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need this join?

Copy link
Author

Choose a reason for hiding this comment

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

Let's say we have a joinTable AB linking A's many_many to B. The original query preserved the order of the items that were fetched from table B by putting their IDs in the FIELD list. This changes that by joining table B so that the original order by used to fetch B items can also be used in this query.

The perfect solution would be to right join the join table to the relation query (line 1350), which removes the need for this query altogether, though I'm not sure what the implications will be. I'll have to look into that.

->addWhere('"' . $parentIDField . '" IN (' . implode(',', $parentIDs) . ')')
->addWhere('"' . $childIDField . '" IN (' . $fetchedIDsAsString . ')')
->addLeftJoin($childTable, "$childTable.ID = $joinTable.$childIDField")
->setOrderBy($fetchedOrderBy)
Copy link
Member

Choose a reason for hiding this comment

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

What is this orderby? How do we know it's what we actually want?

Copy link
Author

Choose a reason for hiding this comment

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

This order by is the replacement for the FIELD order by in the original query as explained in the other comment.

$query = $fetchList->dataQuery()->query();
$fetchedOrderBy = $query->getOrderBy();
$childTables = $query->queriedTables();
$childTable = reset($childTables);
Copy link
Member

Choose a reason for hiding this comment

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

Why do we arbitrarily take the first table?

Copy link
Author

Choose a reason for hiding this comment

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

As far as I could tell this is the only way to derive the base table (the FROM) from a DataList query. An alternative is to grab the table name from the baseClass data object.

I'll add comments to my next commit to make clear what's happening exactly.

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.

2 participants