Рекурсивные отношения Laravel

Я работаю над проектом в Ларавеле . У меня есть модель учетной записи, которая может иметь родителя или может иметь детей, поэтому у меня установлена ​​моя модель:

public function immediateChildAccounts() { return $this->hasMany('Account', 'act_parent', 'act_id'); } public function parentAccount() { return $this->belongsTo('Account', 'act_parent', 'act_id'); } 

Это прекрасно работает. Я хочу, чтобы все дети находились под определенной учетной записью. В настоящее время я делаю это:

 public function allChildAccounts() { $childAccounts = $this->immediateChildAccounts; if (empty($childAccounts)) return $childAccounts; foreach ($childAccounts as $child) { $child->load('immediateChildAccounts'); $childAccounts = $childAccounts->merge($child->allChildAccounts()); } return $childAccounts; } 

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

Есть ли лучшее решение? Должен ли я запускать сырой запрос? У Laravel есть что-то с этим?

В целом я хочу, чтобы для каждой учетной записи получалась каждая дочерняя учетная запись и каждый ребенок ее детей и т. Д. В одном списке / коллекции. Диаграмма:

 A -> B -> D |--> C -> E |--> FG -> H 

Если я запустил A-> instantChildAccounts (), я должен получить {B, C}
Если я запустил A-> allChildAccounts (), я должен получить {B, D, C, E, F} (порядок не имеет значения)

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

Кроме того, я не уверен, что это нормально спросить об этом здесь, но это связано. Как я могу получить список всех учетных записей, которые не включают дочерние учетные записи? Таким образом, в основном обратный этому методу выше. Это значит, что пользователь не пытается предоставить учетную запись родителя, который уже является дочерним. Используя диаграмму сверху, я хочу (в псевдокоде):

Учетная запись :: where (account_id not in (A-> allChildAccounts ())). Поэтому я бы получил {G, H}

Спасибо за понимание.

Solutions Collecting From Web of "Рекурсивные отношения Laravel"

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

 public function childrenAccounts() { return $this->hasMany('Account', 'act_parent', 'act_id'); } public function allChildrenAccounts() { return $this->childrenAccounts()->with('allChildrenAccounts'); } 

Затем:

 $account = Account::with('allChildrenAccounts')->first(); $account->allChildrenAccounts; // collection of recursively loaded children // each of them having the same collection of children: $account->allChildrenAccounts->first()->allChildrenAccounts; // .. and so on - $account = Account::with('allChildrenAccounts')->first(); $account->allChildrenAccounts; // collection of recursively loaded children // each of them having the same collection of children: $account->allChildrenAccounts->first()->allChildrenAccounts; // .. and so on 

Таким образом вы сохраняете много запросов. Это выполнит 1 запрос на каждый уровень вложенности + 1 дополнительный запрос.

Я не могу гарантировать, что он будет эффективен для ваших данных, вам нужно его проверить.


Это для бездетных учетных записей:

 public function scopeChildless($q) { $q->has('childrenAccounts', '=', 0); } 

тогда:

 $childlessAccounts = Account::childless()->get(); 

Я делаю что-то подобное. Я думаю, что ответ заключается в кэшировании вывода и очистке кеша при каждом обновлении базы данных (если ваши учетные записи сами по себе не сильно меняются)