Laravel whereHas приводит к странным

модель продукта

    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

не имеют понятия, запрос выглядит как проблема

предыдущий проект у меня тоже возникли проблемы, в конце я снова использую find и loop вместо использования 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...
            }
        }
    }
}

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

Ответы

Ответ 1

i создал таблицы, упомянутые выше (дающие точно такие же отношения, имена таблиц, имена моделей) и пробовал ваш код (предоставляя жестко закодированные значения)

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}

проверьте, все ли в вашей базе все в порядке, проверьте, что каждый первичный ключ и внешние ключи создаются как "целое число". И проверьте "сортировку" db так же, как и таблицы.

Ответ 2

Это не похоже на Laravel-related (поскольку вы все равно не получаете никаких результатов при запуске запроса непосредственно с помощью 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 ..." ), чтобы увидеть, если вы обнаружите, где проблема начинается.

(Я попытался создать обе таблицы, и оба запроса возвращают корректные результаты, кстати.)

Ответ 3

Прежде всего:

Если вы используете eloquent (метод find), вы можете сделать что-то вроде:

Product::find($id);

и он возвращает модель продукта, где указанный вами идентификатор равен первичному ключу. Сказав это, нет необходимости использовать whereHas(), так как он не будет иметь никакого эффекта. Вместо find() вы можете попробовать get() или first(), например, в зависимости от того, что вы ищете.

Если вы хотите распечатать свой запрос, вы можете завершить его с помощью ->toSql();, и он выведет запрос в виде строки (помогает много!).

Я не уделял много внимания цели, но я уверен, что если вы используете

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

Вы сможете сравнить то, что делаете (поскольку вы знаете, каков должен быть правильный результат или запрос), и сможете понять это.

В конце концов, нам нужно упражняться, чтобы исследовать наш ум!

Ответ 4

попробуйте эту надежду, это поможет вам,

 $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];              
        }
    }

Ответ 5

Я думаю, вы должны изменить свою концепцию отношений в модели продукта из hasMany, чтобы она принадлежала многим.
Также обновите параметры, указав модель страны в качестве первого аргумента, промежуточное имя таблицы как второй аргумент, а затем внешний ключ и первичный ключ как третий и четвертый аргументы. принадлежит ToMany ('App\Models\Country', 'product_country', 'product_id', 'country_id')

Модель продукта

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

Поскольку каждая страна может принадлежать многим продуктам, и каждый продукт может принадлежать многим странам.

Ответ 6

Я знаю, что этот поток немного устарел, но у моей команды действительно была очень похожая проблема с Laravel и whereHas (MySQL EXISTS) на MySQL 5.7.18.

Как только мы обновили MySQL, тот же запрос начал возвращаться точно так, как ожидалось. Я еще не понял, было ли это ошибкой с 5.7.18, но я подозреваю, что это может быть.