You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel如何检索继承自父模型的所有子模型实例?

如何在Eloquent中检索所有继承自同一父模型的子模型记录?

看起来你想实现的是把多个独立数据表的子模型记录,统一以父模型的视角拉取出来——就像调用LivingBeing::all()一样,对吧?Eloquent本身并没有原生支持这种跨表的父模型查询(毕竟每个子模型都绑定了自己的表),不过我们可以通过几种方式来实现你的需求:


方法1:手动合并子模型集合(最简单直接)

既然每个子模型都能独立查询,我们可以分别获取每个子模型的所有记录,再合并成一个Eloquent集合:

use App\Models\Human;
use App\Models\Cat;
use App\Models\Squid;
use Illuminate\Database\Eloquent\Collection;

// 初始化空集合
$allLivingBeings = new Collection();

// 逐个合并子模型的查询结果
$allLivingBeings = $allLivingBeings->merge(Human::all());
$allLivingBeings = $allLivingBeings->merge(Cat::all());
$allLivingBeings = $allLivingBeings->merge(Squid::all());

这样得到的集合里包含了所有子模型的实例,而且因为它们都继承自LivingBeing,所以你可以直接调用父模型的方法(比如isAlive()),完全符合你的需求。


方法2:在父模型封装静态方法(复用性更强)

为了避免每次都重复写合并逻辑,我们可以在LivingBeing模型里添加一个静态方法,把合并的逻辑封装起来:

class LivingBeing extends Model{
    public function isAlive(){
        return $this->is_alive; //boolean
    }

    public static function allLivingBeings()
    {
        $collection = new Collection();
        
        // 列出所有继承自当前父模型的子模型
        $childModels = [Human::class, Cat::class, Squid::class];
        
        foreach ($childModels as $model) {
            $collection = $collection->merge($model::all());
        }
        
        return $collection;
    }
}

之后你只需要调用LivingBeing::allLivingBeings()就能拿到所有记录了,非常方便。

如果需要支持自定义查询条件(比如筛选存活的生物),还可以扩展这个方法,支持传入查询回调:

public static function queryAll($callback = null)
{
    $collection = new Collection();
    $childModels = [Human::class, Cat::class, Squid::class];
    
    foreach ($childModels as $model) {
        $query = $model::query();
        // 如果传入了查询回调,就应用到每个子模型的查询上
        if (is_callable($callback)) {
            $callback($query);
        }
        $collection = $collection->merge($query->get());
    }
    
    return $collection;
}

使用示例:

// 获取所有存活的生物
$aliveBeings = LivingBeing::queryAll(function($query) {
    $query->where('is_alive', true);
});

方法3:数据库UNION查询(大数据量场景)

如果你的子模型数据表数据量很大,多次查询再合并的性能可能不够理想,这时候可以用数据库的UNION操作来合并查询结果:

use Illuminate\Support\Facades\DB;

class LivingBeing extends Model{
    // ... 其他代码
    
    public static function allLivingBeings()
    {
        // 为每个子模型的查询添加一个type字段,方便区分来源
        $humanQuery = Human::select('*', DB::raw('"human" as source_type'));
        $catQuery = Cat::select('*', DB::raw('"cat" as source_type'));
        $squidQuery = Squid::select('*', DB::raw('"squid" as source_type'));
        
        // 合并三个查询
        $unionResults = $humanQuery->union($catQuery)->union($squidQuery)->get();
        
        // 把结果转换成LivingBeing实例(如果不需要子模型的特有方法)
        return self::hydrate($unionResults->toArray());
        
        // 如果需要保留子模型的实例,直接返回unionResults即可
        // return $unionResults;
    }
}

不过要注意:用hydrate生成的是LivingBeing纯父模型实例,会丢失子模型的特有属性和Trait方法(比如hasSpine、hasTentacles里的逻辑)。如果你的业务需要用到子模型的特有功能,还是用前两种方法更合适。


内容的提问来源于stack exchange,提问作者Gabriel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:51:20