【问题标题】:laravel whereHas results weirdlaravel where 结果很奇怪
【发布时间】:2018-03-11 13:44:32
【问题描述】:

产品型号

    public function country() {
        return $this->hasMany('App\Models\ProductCountry', 'product_id', 'id');
    }

控制器

$product = Product::where('mall_' . $this->mall_id, '=', 1)
    ->whereHas('country', function ($i) use ($me) {
        return $i->where('country_id', $me->country_id);
    })
    ->find($key);

原始 SQL:

select * from `product` where `mall_3` = '1' and exists (select * from `product_country` where `product_country`.`product_id` = `product`.`id` and `country_id` = '109') and `product`.`id` = '3' and `product`.`deleted_at` is null limit 1

上面的SQL没有返回结果(当产品id = 3时

下面的 SQL 返回正确的结果(当产品 id = 6 时)

select * from `product` where `mall_3` = '1' and exists (select * from `product_country` where `product_country`.`product_id` = `product`.`id` and `country_id` = '109') and `product`.`id` = '6' and `product`.`deleted_at` is null limit 1

不知道,查询好像没问题

以前的项目我也遇到了这个问题,最后我再次使用查找和循环而不是使用 whereHas,但是这次我再次遇到这个问题并尝试找出原因,但是浪费了几个小时,仍然没有线索,下面是一种解决方法(忽略错误?)

$products = array();
foreach ($request->get('quantity') as $key => $var) {
    if ($var > 0) {
        $product = Product::with(['country'])->where('mall_' . $this->mall_id, '=', 1)
                    ->find($key);

        foreach ($product->country as $c) {
            if ($c->country_id == $me->country_id && !isset($products[$product->id])) {
                //Do something here...
            }
        }
    }
}

【问题讨论】:

  • 您是否尝试过加入表格而不是进行存在检查?
  • 尚未尝试加入,但想知道这个存在检查查询发生了什么,看起来不错但不起作用,真的很奇怪/错误
  • 构造查询后为什么要使用find()
  • 我使用 find 是因为想找到确切的产品,我使用 whereHas 是因为我也希望查询做 VALIDATION,确保没有产品从另一个国家订购,我认为这种方式会阻止用户检查在订单表单中编辑产品 ID 的元素
  • 嗨,我认为你会从 laravel 收集方法中得到很好的利用 (laravel.com/docs/5.4/collections#available-methods)。特别是 'map' 和 'filter' 方法。

标签: php mysql laravel laravel-5 laravel-eloquent


【解决方案1】:

我创建了上面提到的表(给出完全相同的关系、表名、模型名)并尝试了你的代码(通过给出硬编码值)

public function try1(){
    $me = 109;
    $key = 3;
    $product = Product::where('mall_3' , '=', 1)
        ->whereHas('country', function ($i) use ($me) {
            return $i->where('country_id', $me);
        })

        ->find($key);

    return $product;
}

public function try2(){
    $me = 109;
    $key = 6;
    $product = Product::where('mall_3' , '=', 1)
        ->whereHas('country', function ($i) use ($me) {
            return $i->where('country_id', $me);
        })

        ->find($key);

    return $product;
}

但得到了完美的结果

 {"id":3,"mall_1":1,"mall_2":1,"mall_3":1}

{"id":6,"mall_1":1,"mall_2":1,"mall_3":1}

请检查您的数据库是否一切正常,检查每个主键和外键是否都创建为“整数”。并检查数据库和表格的“整理”。

【讨论】:

  • 然后很奇怪,我只是仔细检查,确认 product_country.product_id 是 UNSIGNED INTEGER(10),我还检查了 product_countryproduct TABLE 是相同的排序规则 utf8_unicode_ci跨度>
【解决方案2】:

这似乎与 Laravel 无关(因为直接使用 MyAdmin 运行查询时仍然没有结果)。

select * from `product`
where true
-- and `mall_3` = '1'
and exists (
    select * from `product_country`
    where true
    and `product_country`.`product_id` = `product`.`id`
    and `country_id` = '109'
)
and `product`.`id` = '3'
and `product`.`deleted_at` is null
limit 1

再次运行查询,逐个注释每个where 条件(我添加了true 第一个条件以轻松注释掉所有“and ...”行),看看您是否发现问题开始的地方。

(顺便说一句,我确实尝试创建两个表,两个查询都返回正确的结果。)

【讨论】:

  • 在这样检查之后,我发现deleted_at 不是NULL for product.id = 3,真是个菜鸟错误,谢谢
  • @user259752 但是这怎么可能呢?在您的屏幕截图中,deleted_at 为 NULL。
  • @PaulSpiegel 你是对的,我上次没有查看我的截图,但现在我的数据库已删除_at 真的为空
  • @user259752 所以现在它们都是 null 但 id 3 仍然找不到结果但 id 6 呢?
  • 我尝试将相同的数据导出并导入到我的测试服务器,它正常/工作正常,我尝试在我的 Windows 机器上安装 xampp 并导入相同的数据,它也可以工作,现在看起来只有我的 wampserver 64bit mysql5.7.14 不工作
【解决方案3】:

试试这个,希望对你有帮助,

 $products = array();
    foreach ($request->get('quantity') as $key => $var) {
        if ($var > 0) {
            $product = Product::where('mall_' . $this->mall_id, '=', 1)
                        ->leftjoin('product_country','product_country.product_id','=','product.id')->get();
            $products[$product->id] = ['product_id'=>$product->id,'country_id'=>$product->country_id];              
        }
    }

【讨论】:

    【解决方案4】:

    我认为您应该将产品模型中的关系概念从 hasMany 更改为 belongsToMany。
    还通过将国家模型定义为第一个参数,将中间表名定义为第二个参数,然后将外键和主键定义为第三个和第四个参数来更新参数。 belongsToMany('App\Models\Country', 'product_country','product_id', 'country_id')

    产品型号

    public function country() {
        return $this->belongsToMany('App\Models\Country', 'product_country','product_id', 'country_id');
    }
    

    因为每个国家可能属于多个产品,每个产品可能属于多个国家。

    【讨论】:

      【解决方案5】:

      第一件事:

      如果您使用eloquent(查找方法),您可以执行以下操作:

      Product::find($id);
      

      它会返回一个产品模型,其中您提供的 id 等于主键。话虽如此,没有必要使用whereHas(),因为它没有任何效果。例如,您可以尝试get()first() 而不是find(),具体取决于您要查找的内容。

      如果你想打印出你的查询,你可以用->toSql(); 结束它,它会将查询打印为一个字符串(很有帮助!)。

      我没有太注意目标,但我确定你是否使用了

      dd(Product::where('mall_' . $this->mall_id, '=', 1)
      ->whereHas('country', function ($i) use ($me) {
          return $i->where('country_id', $me->country_id);
      })
      ->toSql());
      

      您将能够比较您正在做的事情(因为您知道正确的结果或查询应该是什么样的)并能够弄清楚。

      毕竟,我们确实需要锻炼来探索我们的思想!

      【讨论】:

      • 我认为这是 mysql 而不是 laravel 的错误,我使用 whereHas 因为系统只向用户显示产品,如果用户在国内,认为 whereHas 也会进行验证,所以不会有订单在这个国家/地区,您可以看到我写的 2 个查询,执行相同但一个得到结果,另一个没有结果,并且查看我上传的图像,已经证明两个查询都应该有结果
      • 我以前使用过 whereHas 并且没有遇到任何问题,但是如果我有时间,我会尝试实现 OP 写的内容,只要我有时间,我就可以提供一些更新此事。我对 laravel 有一点经验(大约 4 个月),但是谈到 Eloquent,我往往会忘记他们有时给出的输出
      【解决方案6】:

      我知道这个线程有点陈旧,但我的团队实际上在 MySQL 5.7.18 上遇到了与 Laravel 和 whereHas (MySQL EXISTS) 非常相似的问题。

      我们升级 MySQL 后,相同的查询开始完全按预期返回。我还没有弄清楚这是否是 5.7.18 的错误,但我怀疑它可能是。

      【讨论】:

        猜你喜欢
        • 2016-05-03
        • 2013-11-03
        • 2016-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-23
        • 2018-05-16
        • 1970-01-01
        相关资源
        最近更新 更多