加入 Eloquent 打破关系?
Posted
技术标签:
【中文标题】加入 Eloquent 打破关系?【英文标题】:Join on Eloquent breaks Relationships? 【发布时间】:2021-08-22 18:15:39 【问题描述】:我有以下关系:
Course
和 Users
之间存在多对多关系,Users
和 Certificates
之间又存在多对多关系。
现在这里是如何从一个课程中获取所有用户的方法,这些用户在同一课程中拥有证书:
$user = $course->users()
->whereHas('certificates', function ($query) use($course)
$query->where('course_certificates.course_id', '=', $course->id);
)->first();
这将返回具有证书$user->certificates
的用户。
这是查询。
SELECT *
FROM "course_users"
WHERE "course_users"."course_id" = ? AND
"course_users"."course_id" IS NOT NULL AND
EXISTS (
SELECT *
FROM "course_certificates"
WHERE "course_users"."id" = "course_certificates"."user_id" AND
"course_certificates"."course_id" = ?
)
如果我改用join
:
$user = $course->users()
->join('course_certificates', 'course_certificates.user_id', '=', 'course_users.id')
->where('course_certificates.course_id', '=', $course->id)
->first();
然后我得到同一个用户,但是$user->certificates
的关系是空的?
SELECT *
FROM "course_users"
INNER JOIN "course_certificates"
ON "course_certificates"."user_id" = "course_users"."id"
WHERE "course_users"."course_id" = ? AND
"course_users"."course_id" IS NOT NULL AND
"course_certificates"."course_id" = ?
这是为什么呢?
【问题讨论】:
我不希望这会有所作为,但如果你渴望通过->with('certificates')
加载certificates
这两个查询,它会改变什么吗?乍一看,我不明白为什么第二种方法对$user->certificates
没有任何作用...
我猜第二种方法会将两个表数据合并到关联数组中。但是 laravel 关系以单独的密钥(如证书)返回连接的表数据。第二种方法,例如在 mysql 中执行查询。我希望使用或 whereha 基于表字段进行内部映射并生成用户友好的结果
在第一种情况下,当您不使用 join 时,它是一个 Eloquent 模型。但是当你使用 join 时,它会变成查询生成器,$user->certificates
不起作用。
@TimLewis 我也会尝试从头开始创建这个示例,也许它与我的版本有关,我在 Laravel 5.6 上
不清楚,您编写了 2 个与用户的多名关系,但在课程和证书之间还有一个数据透视表。您能否分享您的测试代码(在 github 上)以完全重现您所做的事情。
【参考方案1】:
我不是 100% 确定,但如果你使用 join
,我认为 laravel 不理解你加入的任何表,它是一个关系,它只是一个连接,它可能意味着任何东西,但第一个查询您告诉它关系的含义(whereHas
X 关系的一些数据)。
查看源代码,我可以确认我在说什么:join
和 whereHas
(和 has
)。
getRelated()
具有魔力(将数据添加到您的关系中)。看到join
没有做任何事情,它实际上加入了查询,没有其他与关系相关的内容。同样join
来自Query/Builder
,任何其他关于关系的方法都来自Eloquent/Builder
。
【讨论】:
以上是关于加入 Eloquent 打破关系?的主要内容,如果未能解决你的问题,请参考以下文章
Laravel Eloquent 根据数据透视表字段条件获取多对多关系