laravel5.1 eloquent with 通过闭包筛选特定 field 得不到结果的问题
(图片有点大,可右键新tab查看)
User模型
class User extends Model
{
public function profile()
{
return $this->hasMany(UserProfile::class);
}
}
使用with查询某个user及其的profile
User::with(['profile' => function($query) {
$query->select(['id']);
}])->find(4)->toArray()
上面的用法中,我们会发现,即使数据库有记录,sql也记录了对应的查询语句,但是profile关联却是空的,
但是加上外键就可以得到正确结果了:
User::with(['profile' => function($query) {
$query->select(['id', 'user_id']);
}])->find(4)->toArray()
可以查找到正确的profile了。
这和 laravel 框架的工作方式相关,我们先看看下面的例子:
我们使用 DB::listen 方法去记录相关的 sql 语句
这次我们不用find,用get
User::with('profile')->whereIn('id', [3, 4])
->get()->toArray()
我们查看 log 可以发现有以下语句:
select * from `tb_user` where `id` in (?, ?) [3,4]
select * from `tb_user_profile` where `tb_user_profile`.`user_id` in (?, ?) [3,4]
我们可以明显发现,laravel 对于 user 和 user_profile 是独立查询的,
也就是说会得到两个集合,一个是 User、一个是 UserProfile,
但是这并不是我们想要的结果,我们需要的结果是,只有一个 User 集合, 并且这个 User 集合里面有 UserProfile 关联。
但是结果就是这样,如果是你,你会怎么把这些数据关联起来呢?
对了,我们定义关联的时候不是定义了它们的关联方式么?
上面的 hasMany 方法默认第二第三个参数其实就是这两个集合建立关联的关键,第三个参数 user_id、第四个参数 id;
这样一来我们就可以通过比较 UserProfile 的 user_id 和 User 里面的 id,如果相等,则这个 UserProfile 是属于这个 User 的,我们就把该 UserProfile 放进 User 的 profile 关联中,最后就得到我们想要的结果了。
用xdebug证实一下我们的想法:



如我们所想的那样,图一的 match 方法,顾名思义就是匹配了,通过 user 模型集合和 profile 模型集合进行匹配。
图二,也证实了我们模型建立关联需要通过关联中外键的值得想法。
图三,是通过获取 user 的 localkey,也就是 id 的值,来查找 $dictonary 中是否有对应的值,buildDictonary 方法会建立一个关联数组,key 是 user_id(外键)的值,值是关联的数据。这样一样,由于我们没有把 user_id 也select 出来,最后得到的 $dictonary 的结构并不是预期的那样:

其实我们本来是想要得到下面的这种:
[
3 => xxx(UserProfile对象) // 3 是关联的 user_id
]
但是我们得到的却是,所有的 UserProfile 都在一个嵌套的数组里面了,这样一来,下面的 getRelationValue 得到的结果自然就是空的了。
好了,总结一下,就是:laravel 先查询主要的数据(不带with),查询完了之后,取出其中的 id 列数组(不一定都是id啊,只是举个例子),将这个数组作为条件去查找关联,有多少个关联就会再去查找多少次,查找完关联之后通过得到的结果的主键和关联数据的外键比对,相等则建立关联。
总结:在关联筛选 field 的时候,也必须要把关联的外键写进去,否则,即使产生了正确的 sql 语句,但是它们建立不了关联,通过 $user->profile 得到的还是一个空集合。
(对于所有关联都有效哦)
laravel5.1 eloquent with 通过闭包筛选特定 field 得不到结果的问题的更多相关文章
- Swift - 使用闭包筛选过滤数据元素
通常筛选一个数组,通常会在代码的其它地方创建一个函数,然后为数组的每个元素调用它.但这样做会使代码分散在许多地方,不便于阅读.使用闭包就可以将相关代码片断放在一起,使结构逻辑更加清晰. 比如,筛选一个 ...
- pandas_读取Excel并筛选特定数据
# C:\Users\lenovo\Desktop\总结\Python # 读取 Excel 文件并进行筛选 import pandas as pd # 设置列对齐 pd.set_option(&qu ...
- python筛选特定文件的信息按照格式输出到txt
最近搞数据库,为了把图片文件的信息导入数据库表中,我开始研究python列出图片文件,其中发现因为IE临时文件里有非常多的不需要的图片,就需要筛选掉一些文件. 最终用python输出了所有需要的图片文 ...
- laravel5.8 eloquent
https://learnku.com/docs/laravel/5.8/eloquent/3931 示例1: $flights = App\Flight::all(); foreach ($flig ...
- awk 筛选特定长度的序列
awk '/^>/ {printf("\n%s\t",$0);next;} {printf("%s",$0);} END {printf("\n ...
- input="file" 浏览时只显示指定excel文件,筛选特定文件类型
<p>显示 .xls, .xlsx, .csv 文件...</p> <input type="file" accept=".csv, app ...
- nput="file" 浏览时只显示指定excel文件,筛选特定文件类型
<p>显示 .xls, .xlsx, .csv 文件...</p><input type="file" accept=".csv, appl ...
- Lucene in action 笔记 term vector——针对特定field建立的词频向量空间,不存!不会!影响搜索,其作用是告诉我们搜索结果是“如何”匹配的,用以提供高亮、计算相似度,在VSM模型中评分计算
摘自:http://makble.com/what-is-term-vector-in-lucene given a document, find all its terms and the posi ...
- MongoDB全文搜索——目前尚不支持针对特定field的搜索
> db.articles.createIndex( { subject: "text" } ) { "createdCollectionAutomatically ...
随机推荐
- 从零开始的Python学习Episode 10——函数
函数 一.函数的创建 简单格式 def function_name(参数表): 函数体 return 如果没有写return,函数会默认返回一个none 二.函数的参数 必需参数: 调用函数时必需参数 ...
- spring mvc 详细配置
转自: http://www.cnblogs.com/superjt/p/3309255.html 现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是 ...
- 总结在Visual Studio Code创建Node.js+Express+handlebars项目
一.安装node.js环境. Node.js安装包及源码下载地址为:https://nodejs.org/en/download/ 32 位安装包下载地址 : https://nodejs.org/d ...
- 在Asp.Net中使用Redis【本文摘自智车芯官网】
Redis安装 在安装之前需要获取Redis安装包.在这里我们就不详细介绍安装包的获取了.这里Redis-x64-3.2.100.zip安装包为例通过dos命令取安装.通过dos命令找到安装目录. 在 ...
- lintcode-433-岛屿的个数
433-岛屿的个数 给一个01矩阵,求不同的岛屿的个数. 0代表海,1代表岛,如果两个1相邻,那么这两个1属于同一个岛.我们只考虑上下左右为相邻. 样例 在矩阵: [ [1, 1, 0, 0, 0], ...
- 第10章 vim程序编辑器
vi和vim vim是vi的升级版,支持vi的所有指令 vi的使用 vi分为三种模式:一般模式.编辑模式.命令行模式 一般模式 以vi打开一个文件就直接进入一般模式了,这个模式下可以使用上下左右按键来 ...
- Tomcat指定JDK路径
一.应用实例 一般情况下一台服务器只跑一个业务,那么就直接配置一套环境,设置好Java环境变量即可.某些时候一台服务器上会安装多个业务,而且各个业务需要的JDK版本各不相同,或者为了使业务独立开来,需 ...
- PHP中的构造方法和析构方法
构造方法(_ _construct): 构造方法,是一个特殊的方法: 1,名字是固定的:_ _construct: 2,该方法通常都不要我们自己调用,而是在new一个对象的时候会自动调用. 3,该方法 ...
- default.properties文件
在地址栏访问某个 action 之所以能访问到,只因为在 default.properties 配置文件中有一个键值对,key 为struts.action.extension,值为 action,, ...
- vscode如何用浏览器预览运行html文件
1,打开vscode编辑器,点击编辑器主界面左上侧第五个小图标——‘扩展’按钮: 2,进入扩展搜索右拉框,在应用商店搜索框中输入“view in browser”会自动进行搜索 3,等待几秒钟时间,扩 ...