Я работаю над проектом в Ларавеле . У меня есть модель учетной записи, которая может иметь родителя или может иметь детей, поэтому у меня установлена моя модель:
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}
Спасибо за понимание.
Вот как вы можете использовать рекурсивные отношения:
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();
Я делаю что-то подобное. Я думаю, что ответ заключается в кэшировании вывода и очистке кеша при каждом обновлении базы данных (если ваши учетные записи сами по себе не сильно меняются)