HasManyThrough 不够灵活? 猥琐发育,别浪!
假设有三张表
模型 | 主键 | 其余字段 |
---|---|---|
posts | id | |
tags | id | |
post_tags | post_id | tag_id |
使用 HasManyThrough
是很好给 Post
关联上的 Tag
模型的。
但如果这样的情况呢?
模型 | 主键 | 其余字段 |
---|---|---|
users | id | |
user_children | user_id | child_id |
释义:
用户 User
模型拥有多个子模型 User
,且通过 UserChild.user_id = :用户id
查到 User.id=UserChild.child_id
的子 User
。
我们尝试建立两个模型
- app\Models\User.php
<?php
namespace App\Models;
class User extends \Eloquent
{
/**
* 子用户
*
* @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
*/
public function children()
{
return $this->hasManyThrough(User::class, UserChild::class, 'user_id', 'id', 'id');
}
}
- app\Models\UserChild.php
<?php
namespace App\Models;
class UserChild extends \Eloquent
{
/**
* 用户
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user() {
return $this->belongsTo(User::class, 'id', 'user_id');
}
/**
* 子用户
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function child() {
return $this->hasOne(User::class, 'id', 'child_id');
}
}
通过这种写法,我们查询的时候执行的SQL并不是我们预期的那样
select
`users`.*,
`user_children`.`user_id`
from
`users`
inner join `user_children` on `user_children`.`id` = `users`.`id` // 这里的 `user_children`.`id` 是大大的错误,因为需要通过user_children.child_id 来关联回User模型
where
`user_children`.`user_id` = :id
and `users`.`deleted_at` is null
解决方法
- 把
app/Models/User.php
的children方法修改成
<?php
...
/**
* 子用户
*
* @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
*/
public function children()
{
return $this->hasManyThrough(User::class, Relations\UserChildRelation::class, 'user_id', 'id', 'id');
}
}
- 新建
app/Models/Relations/UserChildRelation.php
<?php
namespace App\Models\Relations;
class UserChildRelation extends \App\Models\UserChild
{
protected $primaryKey = 'child_id';
}
然后测试
select
`users`.*,
`user_children`.`user_id`
from
`users`
inner join `user_children` on `user_children`.`child_id` = `users`.`id`
where
`user_children`.`user_id` = :id
and `users`.`deleted_at` is null
正常!
:+1:
666
那么,为什么不在 User 表加个 parent_id :laughing:
@Hanson :unamused: