简体   繁体   English

Laravel One to Many中的一对多关系

[英]Laravel One to Many of One to Many relationship

Currently I'm doing a project with: 目前我正在做一个项目:

  • Invoice->hasMany Items Invoice-> hasMany Items
  • Item->hasMany SubItems Item-> hasMany SubItems

My code is: 我的代码是:

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

This works well until an Invoice has too many Items and each Items has too many SubItems and PHP return with a timeout. 这很有效,直到Invoice包含太多Items并且每个Items有太多SubItems并且PHP返回超时。 Does anybody have any other better solution? 有没有人有其他更好的解决方案?

The relations are lazy loaded, so for each item a new database connection is opened. 这些关系是延迟加载的,因此对于每个项目,都会打开一个新的数据库连接。 This takes some time. 这需要一些时间。

You can eager load the relations with: Invoice::with('subitems')->find($id) . 您可以急切加载关系: Invoice::with('subitems')->find($id) More about this at: https://laravel.com/docs/5.7/eloquent-relationships#eager-loading . 有关详情,请访问: https//laravel.com/docs/5.7/eloquent-relationships#eager-loading

First, I think you have a mistake in your code. 首先,我认为您的代码中存在错误。 Instead of $invoice->$items , you probably meant $invoice->items . 而不是$invoice->$items ,你可能意味着$invoice->items

The answer to your question could be to do eager load. 你的问题的答案可能是急切加载。 Instead of: 代替:

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

try: 尝试:

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

This way everything will be loaded in one query. 这样一切都将在一个查询中加载。 You are currently doing count($invoice->items) + 1 queries. 您目前正在count($invoice->items) + 1查询。 This is called the N + 1 problem and it is very common and important to be aware of. 这被称为N + 1问题,它是非常常见和重要的。

$invoice = Invoice::with(array('items','items.subItems')->where('id',$id)->get();

Update the time allowed with set_time_limit for the thread as each item is iterated over: 在迭代每个项目时,更新线程的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;

This still means a request will be taking a large amount of time, but it will only take $allowed_seconds_per_row seconds per row iterated over. 这仍然意味着请求将花费大量时间,但每行迭代只需要$allowed_seconds_per_row秒。 If one row takes longer than expected it will sill time out. 如果一行花费的时间比预期的要长,那么它会耗费时间。

Other options are to move the process to cli and adjust the max execution time for that to account for the worst case. 其他选项是将流程移至cli并调整最大执行时间以解决最坏情况。

try this: 尝试这个:

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

and in Invoice model: 并在发票模型中:

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

in Items model: 在项目模型中:

public function subItems() {
    return $this->hasMany(SubItem::class, 'foreign_id', 'id')->where('rank' ,$this->rank);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM