Laravel От одного ко многим От одного ко многим - PullRequest
0 голосов
/ 14 сентября 2018

В настоящее время я делаю проект с:

  • Счет-фактура-> Имеет много предметов
  • Item-> hasMany SubItems

Мой код:

$invoice = Invoice::find($id);
foreach($invoice->items as $item) {
    $item->subItems;
}
return $invoice;

Это работает хорошо, пока в Счете не будет слишком много Предметов, а у каждого Предмета слишком много Подэлементов, а PHP вернет время ожидания. У кого-нибудь есть какое-нибудь другое лучшее решение?

Ответы [ 5 ]

0 голосов
/ 14 сентября 2018
$invoice = Invoice::with(array('items','items.subItems')->where('id',$id)->get();
0 голосов
/ 14 сентября 2018

попробуйте это:

$invoice = Invoice::with('items.subItems')->find($id);

и в инвойсе модель:

public function items() { 
    return $this->hasMany(Item::class, 'foreign_id', 'id')->orderBy('rank');
}

в модели элементов:

public function subItems() {
    return $this->hasMany(SubItem::class, 'foreign_id', 'id')->where('rank' ,$this->rank);
}
0 голосов
/ 14 сентября 2018

Отношения загружаются лениво, поэтому для каждого элемента открывается новое соединение с базой данных. Это займет некоторое время.

Вы можете загрузить отношения с: Invoice::with('subitems')->find($id). Подробнее об этом: https://laravel.com/docs/5.7/eloquent-relationships#eager-loading.

0 голосов
/ 14 сентября 2018

Во-первых, я думаю, что в вашем коде есть ошибка. Вместо $invoice->$items вы, вероятно, имели в виду $invoice->items.

Ответом на ваш вопрос может стать стремительная нагрузка. Вместо:

$invoice = Invoice::find($id);

попробовать:

$invoice = Invoice::with([
'items' => function ($q) {
    $q->with('subItems');
    }
])->find($id);

Таким образом, все будет загружено в одном запросе. В настоящее время вы делаете count($invoice->items) + 1 запросов. Это называется проблемой N + 1, и об этом очень важно знать.

0 голосов
/ 14 сентября 2018

Обновите время, разрешенное с set_time_limit для потока, так как каждый элемент повторяется:

$invoice = Invoice::find($id);
$allowed_seconds_per_row = 3;
foreach($invoice->$items as $item){
    set_time_limit($allowed_seconds_per_row);
    $item->subItems();
}
return $invoice;

Это по-прежнему означает, что запрос будет занимать много времени, но это займет всего $allowed_seconds_per_row секунд на повторяемую строку. Если один ряд занимает больше времени, чем ожидалось, это приведет к превышению времени ожидания.

Другие варианты: переместить процесс на cli и настроить максимальное время выполнения для этого, чтобы учесть наихудший случай.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...