雄辩的急切的加载顺序

我有雄辩的查询问题。 我正在使用急切的加载(一对一的关系)来获得“ 学生 ”与“ 考试 ”,使用下面的代码。

Student::with('exam')->orderBy('exam.result', 'DESC')->get() 

而且我想通过“ 考试 ”中的“ 结果 ”列来订购收到的行。 我在用

 ->orderBy('exam.result', 'DESC') 

但它不工作。 任何想法如何做到这一点?

尝试这个:

 Student::with(array('exam' => function($query) { $query->orderBy('result', 'DESC'); })) ->get(); 

如果您需要通过结果列来订购学生馆藏,则需要join表格。

 Student::with('exam') ->join('exam', 'students.id', '=', 'exam.student_id') ->orderBy('exam.result', 'DESC') ->get() 

在这种情况下,假设你有一个专栏student_id ,你的考试表被命名为exam

TL;博士

 Student::with('exam')->get()->sortByDesc('exam.result'); 

这将使用集合方法而不是MySQL ORDER BY预先加载后的查询结果进行sorting。

说明

当你急于加载时,你不能在加载的关系上使用ORDER BY ,因为第二个查询的结果会被请求和汇编。 正如你可以在Laravel文档中看到的那样,在2个查询中发生急切的加载。

如果你想使用MySQL的ORDER BY你必须join相关的表。

作为一种解决方法,您可以运行您的查询并使用sortBysortByDesc或者sort 。 与解决scheme相比,此解决scheme具有优点和缺点:

优点:

  • 你保持雄辩的function。
  • 更短,更直观的代码。

缺点:

  • sorting将由PHP而不是数据库引擎完成。
  • 除非您为分拣机function提供自定义closures , 否则只能按单列进行sorting 。
  • 如果你只需要一部分查询的有序结果(例如ORDER BY LIMIT ),那么你必须获取所有东西 ,sorting,然后过滤sorting的结果,否则最终只会筛选被过滤的部分(sorting将不会考虑过滤掉的元素)。 所以这个解决scheme只有在你处理整个数据集或者开销不是问题时才可以接受。

这对我工作:

 $query = Student::select(['id','name']); $query->has('exam')->with(['exam' => function ($query) { return $query->orderBy('result','ASC'); }]); return $query->get(); 

你可以使用\ Illuminate \ Database \ Eloquent \ Relations \ Relation和查询范围来添加远列的关系,我为此写了一个特性,它错过了HasOne或HasMany,但是可以很容易地使用BelongsTo和BelongsToMany

此外,该方法可以增强支持多个链接关系的深度1以上,我为此提供了空间

 <?php /** * User: matteo.orefice * Date: 16/05/2017 * Time: 10:54 */ use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Builder; trait WithFarColumnsTrait { public function scopeWithFarColumns(Builder $query , $relationPath , $columns , $tableAliasPrefix = null) { $relationPath = array_wrap($relationPath); $tableAliasPrefix = $tableAliasPrefix ?: WithFarColumnsTrait::randomStringAlpha(3); $currentModel = $this; $subQueries = []; $relationIndex = 0; foreach ($relationPath as $relationName) { if (method_exists($currentModel , $relationName)) { $relation = $currentModel->$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 <COLUMNs> } // 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 <COLUMNs> } else { throw new \InvalidArgumentException( sprintf("Relation $relationName of type %s is not supported" , get_class($relation)) ); } $currentModel = $relatedModel; $relationIndex++; } // end foreach <RELATIONs> } /** * @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; } } 

有一种替代的方式来实现你想要的结果而不使用连接。 您可以根据考试成绩对学生进行sorting。 (Laravel 5.1):

 $students = Student::with('exam')->get(); $students = $students->sortByDesc(function ($student, $key) { return $student->exam->result; }); 
Interesting Posts