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

如何在Laravel中定义带OR条件的关联关系并支持预加载

在Laravel中实现User与UserConnection的OR条件关联(兼容原生关联特性)

要实现User模型通过user_connections表的from_user_id或to_user_id关联到UserConnection模型,同时完全兼容Laravel原生关联的所有特性(预加载、链式查询等),可以通过自定义关联类扩展原生的HasMany关联,支持OR条件判断。

步骤1:创建自定义HasManyOr关联类

这个类继承自Laravel原生HasMany,重写关联约束和预加载约束逻辑,替换为OR条件:

<?php

namespace App\Models\Relations;

use Illuminate\Database\Eloquent\Relations\HasMany;

class HasManyOr extends HasMany
{
    protected $otherForeignKey;

    public function __construct($query, $parent, $foreignKey, $otherForeignKey, $localKey)
    {
        $this->otherForeignKey = $otherForeignKey;
        parent::__construct($query, $parent, $foreignKey, $localKey);
    }

    /**
     * 添加强制关联约束
     */
    public function addConstraints()
    {
        if (static::$constraints) {
            $foreignKey = $this->getForeignKeyName();
            $otherForeignKey = $this->otherForeignKey;
            $localKey = $this->getLocalKeyName();

            $this->query->where(function ($query) use ($foreignKey, $otherForeignKey, $localKey) {
                $query->where($foreignKey, '=', $this->parent->{$localKey})
                      ->orWhere($otherForeignKey, '=', $this->parent->{$localKey});
            });
        }
    }

    /**
     * 添加预加载时的批量约束
     */
    public function addEagerConstraints(array $models)
    {
        $localKey = $this->getLocalKeyName();
        $keys = $this->getKeys($models, $localKey);

        if (empty($keys)) {
            $this->query->whereRaw('1=0');
            return;
        }

        $foreignKey = $this->getForeignKeyName();
        $otherForeignKey = $this->otherForeignKey;

        $this->query->where(function ($query) use ($foreignKey, $otherForeignKey, $keys) {
            $query->whereIn($foreignKey, $keys)
                  ->orWhereIn($otherForeignKey, $keys);
        });
    }
}

步骤2:在User模型中定义关联方法

在User模型中添加userConnections关联方法,使用自定义的HasManyOr关联:

<?php

namespace App\Models;

use App\Models\Relations\HasManyOr;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    // ... 你的其他模型代码

    /**
     * 获取用户的所有连接记录(作为发起者或接收者)
     */
    public function userConnections()
    {
        return $this->newHasManyOr(
            $this->newQueryForRelation(UserConnection::class),
            $this,
            'from_user_id',
            'to_user_id',
            $this->getKeyName()
        );
    }

    /**
     * 实例化自定义的HasManyOr关联
     */
    protected function newHasManyOr($query, $parent, $foreignKey, $otherForeignKey, $localKey)
    {
        return new HasManyOr($query, $parent, $foreignKey, $otherForeignKey, $localKey);
    }
}

使用方式

现在你可以像使用Laravel原生关联一样操作这个关联:

  • 延迟加载:
$user = User::find(1);
$connections = $user->userConnections;
  • 预加载(避免N+1查询):
$users = User::with('userConnections')->get();
foreach ($users as $user) {
    echo $user->userConnections->count();
}
  • 链式添加额外查询条件:
$recentConnections = $user->userConnections()
    ->where('created_at', '>', now()->subMonth())
    ->orderBy('created_at', 'desc')
    ->get();

方案优势

  • 完全适配现有数据库表结构,无需修改字段或添加迁移
  • 100%兼容Laravel原生关联特性,团队成员可无缝使用
  • 代码结构符合Laravel关联扩展规范,易于维护

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 01:55:10