I'm working on a project in Laravel. I have an Account model that can have a parent or can have children, so I have my model set up like so:

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

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

This works fine. What I want to do is get all children under a certain account. Currently, I'm doing this:

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有办法处理吗?

In summary

A -> B -> D
|--> C -> E
     |--> F 
G -> H

If I run A->immediateChildAccounts(), I should get {B, C}
If I run A->allChildAccounts(), I should get {B, D, C, E, F} (order doesn't matter)

Again, my method works, but it seems like I'm doing way too many queries.

另外,我不确定在这里问这个是否合适,但这是相关的.如何获得包含don't个子帐户的所有帐户的列表?所以基本上与上述方法相反.这样,用户就不会试图给一个帐户指定一个已经是其子帐户的父帐户.使用上面的图表,我想要(在伪代码中):

Account::where(account_id not in (A->allChildAccounts())). So I would get {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

这样可以节省大量查询.这将在每个嵌套级别上执行1个查询+1个附加查询.

I can't guarantee it will be efficient for your data, you need to test it definitely.


这适用于无子女账户:

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

然后:

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

Laravel相关问答推荐

在 Laravel 中排序的集合在 Vue 中突然不再排序

如何使用 laravel 更新单个值

Laravel phpunit 测试失败并出现 PDOException:SQLSTATE[HY000]:一般错误:1 接近0:语法错误

Npm run dev 卡在 APP_URL

Laravel 有Many Many to Many To One Eloquent

使用 Amazon S3 的 Storage::get() 返回 false

Laravel 附加额外字段

Laravel中具有两个外键字段的数据库一对多

Laravel Auth::attempt() 返回 false

如何在没有 Artisan 的情况下运行 Laravel?

如何使用中间件将标头添加到响应中?

在 Eloquent 中按自定义顺序对集合进行排序

Laravel 5 环境配置数组?

我如何从给定的日期时间 struct 创建Carbon 对象?

使用 Laravel 创建新项目会引发异常

在 Laravel 中按用户名查找用户

在 Laravel 的数据透视表中添加 id 列有什么好处?

Mac OS X 需要 Mcrypt PHP 扩展

Laravel 用户能力

Distinct values with pluck