• 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 得到的还是一个空集合。

    (对于所有关联都有效哦)

  • 相关阅读:
    使用通配符查询
    使用聚合函数查询
    有趣的图标
    利用Office Chart 制作柱图(一个柱子)
    众多select
    对象不能从 DBNull 转换为其他类型。
    使用谓词进行查询
    使用数学函数查询
    学生信息表 通过选择年级和班级得到详细的学生信息名单
    使用时间函数查询
  • 原文地址:https://www.cnblogs.com/eleven24/p/8213372.html
Copyright © 2020-2023  润新知