Яркая нетерпеливая загрузка
У меня проблема с красноречивым запросом. Я использую нетерпеливую загрузку (отношения один к одному), чтобы получить « студент » с « экзаменом », используя приведенный ниже код.
Student::with('exam')->orderBy('exam.result', 'DESC')->get()
И я хочу заказать полученные строки по столбцу « результат » в « exam ». я использую
->orderBy('exam.result', 'DESC')
Но это не работает. Есть идеи, как это сделать?
- Laravel 4: Не удалось открыть stream: разрешение отклонено
- Laravel перенаправляет обратно в исходное место после входа в систему
- Аутентификация с помощью двух разных таблиц
- Laravel - Route :: resource vs Route :: controller
- Как установить тайм-аут сеанса в Laravel 4.2?
- Laravel перенаправить все запросы на HTTPS
- Каковы лучшие практики и лучшие места для помощников laravel 4 или основных функций?
- Как установить Laravel 4 в подпапку веб-хостинга без публичной публикации / приложения / папки?
- глобальная переменная для всех controllerов и просмотров
- Laravel. Используйте scope () в моделях с отношением
- Миграция: не удается добавить ограничение внешнего ключа в laravel
- Красноречивый сбор: подсчет и обнаружение пустых
- Laravel перенаправляет обратно с помощью () сообщения
Попробуй это:
Student::with(array('exam' => function($query) { $query->orderBy('result', 'DESC'); })) ->get();
Если вам нужно заказать коллекцию студентов по столбцу результата, вам нужно будет присоединиться к таблицам.
Student::with('exam') ->join('exam', 'students.id', '=', 'exam.student_id') ->orderBy('exam.result', 'DESC') ->get()
В этом случае, если у вас есть столбец student_id
и ваша таблица экзаменов называется exam
.
Это сработало для меня:
$query = Student::select(['id','name']); $query->has('exam')->with(['exam' => function ($query) { return $query->orderBy('result','ASC'); }]); return $query->get();
ТЛ; др
Student::with('exam')->get()->sortByDesc('exam.result');
Это отсортирует результаты запроса после активной загрузки с использованием методов сбора, а не с помощью MySQL ORDER BY
.
объяснение
Когда вы загружаете загрузку, вы не можете использовать ORDER BY
для загруженных отношений, потому что они будут запрошены и собраны в результате второго запроса. Как вы можете видеть это в документации Laravel, загруженная загрузка происходит в 2 запросах.
Если вы хотите использовать MySQL ORDER BY
вы должны присоединиться к связанным таблицам.
В качестве обходного пути вы можете запустить свой запрос и отсортировать полученный набор с помощью sortBy
, sortByDesc
или даже sort
. Это решение имеет преимущества и недостатки над решением соединения:
Преимущества:
- Вы сохраняете Eloquent функциональность.
- Более короткий и интуитивно понятный код.
Недостатки:
- Сортировка будет выполняться PHP вместо механизма базы данных.
- Вы можете сортировать только по одному столбцу, если только вы не предоставляете пользовательское закрытие функций сортировщика .
- Если вам нужна только часть упорядоченных результатов запроса (например,
ORDER BY
сLIMIT
), вы должны получить все , заказать, а затем отфильтровать упорядоченный результат, иначе вы получите только отфильтрованную часть, заказываемую (заказ не будут рассматривать отфильтрованные элементы). Таким образом, это решение приемлемо только тогда, когда вы все равно будете работать со всем набором данных, или накладные расходы не являются проблемой.
Если вы ВСЕГДА хотите, чтобы он был отсортирован по результатам экзамена, вы можете добавить вызов sortBy непосредственно в функцию отношений на модели.
public function exam() { return this->hasMany(Exam::class)->orderBy('result'); }
(кредит для этого ответа идет навстречу – он ответил на это здесь: как сортировать ядовитый подзапрос )
Вы можете использовать \ Illuminate \ Database \ Eloquent \ Relations \ Relation и области запросов для добавления далекого столбца через отношения, я написал для этого черты, он пропускает HasOne o HasMany, но с BelongsTo и BelongsToMany можно легко адаптировать
Кроме того, этот метод можно было бы усилить, чтобы поддерживать больше, чем глубина 1 для отношений с несколькими цепями, я создал место для этого
$relationName(); } else { throw new BadMethodCallException("Relationship $relationName does not exist, cannot join."); } $currentTable = $currentModel->getTable(); if ($relationIndex == 0) { $query->addSelect($currentTable . '.*'); } $relatedModel = $relation->getRelated(); /** * @var string */ $relatedTable = $relatedModel->getTable(); if ($relation instanceof BelongsTo) { foreach ($columns as $alias => $column) { $tableAlias = $tableAliasPrefix . $relationIndex; $tableAndAlias = $relatedTable . ' AS ' . $tableAlias; /** * Al momento gestisce soltanto la prima relazione * todo: navigare le far relationships e creare delle join composte */ if (!isset($subQueries[$alias])) { $subQueries[$alias] = $currentQuery = DB::query() ->from($tableAndAlias) ->whereColumn( $relation->getQualifiedForeignKey() , // 'child-table.fk-column' '=' , $tableAlias . '.' . $relation->getOwnerKey() // 'parent-table.id-column' ) ->select($tableAlias . '.' . $column); // se la colonna ha una chiave stringa e' un alias /** * todo: in caso di relazioni multiple aggiungere solo per la piu lontana */ if (is_string($alias)) { $query->selectSub($currentQuery , $alias); } else { throw new \InvalidArgumentException('Columns must be an associative array'); } } else { throw new \Exception('Multiple relation chain not implemented yet'); } } // end foreach } // endif else if ($relation instanceof BelongsToMany) { foreach ($columns as $alias => $column) { $tableAlias = $tableAliasPrefix . $relationIndex; $tableAndAlias = $relatedTable . ' AS ' . $tableAlias; if (!isset($subQueries[$alias])) { $pivotTable = $relation->getTable(); $subQueries[$alias] = $currentQuery = DB::query() ->from($tableAndAlias) ->select($tableAlias . '.' . $column) // final table vs pivot table ->join( $pivotTable , // tabelle pivot $relation->getQualifiedRelatedKeyName() , // pivot.fk_related_id '=' , $tableAlias . '.' . $relatedModel->getKeyName() // related_with_alias.id ) ->whereColumn( $relation->getQualifiedForeignKeyName() , '=' , $relation->getParent()->getQualifiedKeyName() ); if (is_string($alias)) { $query->selectSub($currentQuery , $alias); } else { throw new \InvalidArgumentException('Columns must be an associative array'); } } else { throw new \Exception('Multiple relation chain not implemented yet'); } } // end foreach } else { throw new \InvalidArgumentException( sprintf("Relation $relationName of type %s is not supported" , get_class($relation)) ); } $currentModel = $relatedModel; $relationIndex++; } // end foreach } /** * @param $length * @return string */ public static function randomStringAlpha($length) { $pool = array_merge(range('a', 'z'),range('A', 'Z')); $key = ''; for($i=0; $i < $length; $i++) { $key .= $pool[mt_rand(0, count($pool) - 1)]; } return $key; } }
Существует альтернативный способ достижения результата, который вы хотите использовать без использования объединений. Вы можете сделать следующее, чтобы отсортировать учащихся по результатам их экзамена. (Laravel 5.1):
$students = Student::with('exam')->get(); $students = $students->sortByDesc(function ($student, $key) { return $student->exam->result; });