2014-10-30 3 views
16

Я работаю над проектом в Laravel. У меня есть модель счета, который может иметь один из родителей или может иметь детей, поэтому у меня есть моя модель создана таким образом: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 
    |--> F 
G -> H 

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

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

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

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

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

ответ

34

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

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 

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

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


Это для бездетных счетов:

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

затем:

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

Это не то, что я пытаюсь сделать. Мне нужны все дочерние аккаунты в одной коллекции. Метод, который я предоставил, делает это, я просто не уверен, насколько он эффективен. Кроме того, второе решение не то, что я ищу. Мне нужны все учетные записи, которые не являются дочерними элементами учетной записи, вызывающей функцию, а не бездетными учетными записями. – Troncoso

+0

1 Это то, что вы делаете прямо сейчас, только вы вызываете db-запрос в N раз больше, чем с предлагаемым решением. 2 затем перефразируйте свой вопрос, потому что это не то, что вы написали. Даже теперь, после вашего комментария, неясно, что вы спрашиваете - прямые дети? потомки? –

+0

Ничего себе. ты гений. Теперь мой код в два раза быстрее :) –

1

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

Смежные вопросы