Laravel渴望加载数据透视表关系

时间:2019-08-14 14:31:30

标签: mysql laravel model

在使用聊天应用程序时,我已经看了很多时间了,但是我似乎无法理解如何实现以下目标:

我所拥有的: 3张桌子:

  1. 客户

  2. 频道

  3. channel_client(数据透视表)

2种型号:

  1. App \ Clients

    class Client extends Model
    {
        protected $table = "clients";
    
    public function channels() {
        return $this->belongsToMany(Channel::class);
    } ...
    
  2. 应用程序\频道

    class Channel extends Model
    public function clients() {
        return $this->belongsToMany(Client::class);
    } ...
    

我想要实现的目标: 获取包含客户端X和客户端Y以及其他任何内容的频道。 (我可以通过客户端模型预先访问客户端ID)

我尝试了一下修改,结果如下:

>>> $client = App\Client::with('channels')->whereIn('id',[1,2])->get()
=> Illuminate\Database\Eloquent\Collection {#3303
     all: [
       App\Client {#3243
         id: 1,
         name: "John",
         user_id: 1,
         created_at: "2019-08-14 12:55:19",
         updated_at: "2019-08-14 12:55:19",
         channels: Illuminate\Database\Eloquent\Collection {#3354
           all: [
             App\Channel {#3249
               id: 1,
               name: "Web Development",
               type: null,
               created_at: "2019-08-14 12:52:32",
               updated_at: "2019-08-14 12:52:32",
               pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3362
                 client_id: 1,
                 channel_id: 1,
               },
             },
             App\Channel {#3360
               id: 3,
               name: "iOS Development",
               type: null,
               created_at: "2019-08-14 12:52:32",
               updated_at: "2019-08-14 12:52:32",
               pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3321
                 client_id: 1,
                 channel_id: 3,
               },
             },
             App\Channel {#3363
               id: 5,
               name: "Android Development",
               type: null,
               created_at: "2019-08-14 12:52:32",
               updated_at: "2019-08-14 12:52:32",
               pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3329
                 client_id: 1,
                 channel_id: 5,
               },
             },
           ],
         },
       },
       App\Client {#3283
         id: 2,
         name: "Lucy",
         user_id: 2,
         created_at: null,
         updated_at: null,
         channels: Illuminate\Database\Eloquent\Collection {#3286
           all: [
             App\Channel {#3364
               id: 1,
               name: "Web Development",
               type: null,
               created_at: "2019-08-14 12:52:32",
               updated_at: "2019-08-14 12:52:32",
               pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3248
                 client_id: 2,
                 channel_id: 1,
               },
             },
           ],
         },
       },
     ],
   }
>>> 

正如您在此处看到的那样,ID为1的频道是用户的相互频道,因为用户1和用户2都订阅了频道1。

我知道我的查询会返回所有用户及其用户ID为1或2的频道,但是如果我将其转过来并查询App \ Channel :: with('users')...我无法指定位置子句,因为我不知道这是相互的频道ID。这就是我要尝试查询的内容。 所以这是总结: 我想要一个 Eagerloading Query (否则,我将使用whereHas),它返回我指定的客户的相互渠道。 非常感谢您的阅读。 我希望您能帮助我理解这一点。 问候!

编辑:因此,按This Laravel Documentation Part判断,它应该按照@Mohamed Ahmed的描述工作,但是当我尝试时,我得到以下结果,其中似乎已加载了所有通道,但也加载了我指定的客户端(但仍然查询所有频道,这不是我真正的目标)

    >>> $cha = App\Channel::with(['clients' => function($q){ $q->whereIn('id',[1,2]); }])->get();
=> Illuminate\Database\Eloquent\Collection {#3359
     all: [
       App\Channel {#3365
         id: 1,
         name: "Web Development",
         type: null,
         created_at: "2019-08-14 12:52:32",
         updated_at: "2019-08-14 12:52:32",
         clients: Illuminate\Database\Eloquent\Collection {#3403
           all: [
             App\Client {#3398
               id: 1,
               name: "John Doe",
               user_id: 1,
               created_at: "2019-08-14 12:55:19",
               updated_at: "2019-08-14 12:55:19",
               pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3324
                 channel_id: 1,
                 client_id: 1,
               },
             },
             App\Client {#3240
               id: 2,
               name: "Lucy",
               user_id: 2,
               created_at: null,
               updated_at: null,
               pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3372
                 channel_id: 1,
                 client_id: 2,
               },
             },
           ],
         },
       },
       App\Channel {#3325
         id: 2,
         name: "Android Development",
         type: null,
         created_at: "2019-08-14 12:52:32",
         updated_at: "2019-08-14 12:52:32",
         clients: Illuminate\Database\Eloquent\Collection {#3268
           all: [],
         },
       },
       ... all the remaining channels here (too much code)

所以这是部分正确的。有想法吗?

1 个答案:

答案 0 :(得分:0)

您绝对可以扭转它。但这将意味着要修补(得到双关语?)。

您要做的是访问Channel模型并执行whereHas('users')。魔术发生在这里:

$channel = App\Channel::whereHas('clients', function($q){
  $q->whereIn('id', [1,2])->get();
})->get()

您可以在控制器中尝试此操作或将其作为返回值。

这基本上是做的,它称为clients关系并在该关系内运行条件。如果您正确设置了关系(正确设置了许多与数据透视表的关系),则应该没有任何其他问题。因此,现在上面的代码将采用所有ID为1和2的客户端的渠道。

希望这会有所帮助。

快乐编码:)