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, но я подозреваю, что это может быть.