Проверьте, существует ли отношение belongsToMany-Laravel

Проверьте, существует ли отношение belongsToMany-Laravel

03.07.2014 05:56:55 Просмотров 20 Источник

Две из моих таблиц (клиенты и продукты)имеют отношение ManyToMany, используя blongToMany Laravel и сводную таблицу. Теперь я хочу проверить, есть ли у определенного клиента определенный продукт.

Я мог бы создать модель для проверки сводной таблицы, но поскольку Laravel не требует этой модели для метода belongsToMany, мне было интересно, есть ли другой способ проверить, существует ли определенная связь, не имея модели для сводной таблицы.

У вопроса есть решение - Посмотреть?

Ответы - Проверьте, существует ли отношение belongsToMany-Laravel / Check if belongsToMany relation exists - Laravel

Является ответом!
alexrussell

03.07.2014 06:06:44

Я думаю, что официальный способ сделать это-сделать:

$client = Client::find(1);
$exists = $client->products->contains($product_id);

Это несколько расточительно в том смысле, что он выполняет SELECT, а затем, наконец, выполняет Collectionнад foreach, чтобы найти модель с идентификатором, который вы передаете. Однако для этого не требуется моделирование сводной таблицы.

Если вам не нравится расточительность этого, вы можете сделать это самостоятельно в SQL / Query Builder, что также не потребует моделирования таблицы (и не потребует получения Collectionмодели, если у вас ее еще нет для других целей:

Client
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/24555932#comment41372684_24555932
+1. Это официальный способ и должен быть отмечен как лучший ответ.
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/24555932#comment47782462_24555932
@DavidMIRV вы получаете эту ошибку из верхнего образца кода? Если да, то уверены ли вы, что называете отношения атрибутом? Если вы сделаете это как вызов метода (т. е. $exists = $client->products()->contains($product_id);), то он действительно скажет, что containsне существует на BelongsToMany. Тем не менее, если вы вызываете его как атрибут, то объект BelongsToMany автоматически преобразуется в коллекцию, которая содержит contains().
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/24555932#comment47842790_24555932
да, я исправил это, я не могу точно вспомнить, в чем была проблема, но я думаю, что я пропустил :: with
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/24555932#comment83142747_24555932
@GustavoStraube этот метод работает, но он будет загружать много данных в память только для проверки существования отношений.
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/24555932#comment83143641_24555932
@AlexeyMezenin да, я согласен с вами. В моем случае, однако, я уже загружаю соответствующие модели в любом случае. Так что никаких дополнительных данных не загружается. В любом случае, спасибо за понимание. Возможно, это поможет другим людям прийти к такому ответу.
nielsiano

03.07.2014 06:10:33

Update: я не принял во внимание полезность проверки множественных отношений, если это так, то @deczo имеет лучший ответ на этот вопрос. Запуск только одного запроса для проверки всех отношений является желаемым решением.

    /**
     * Determine if a Client has a specific Product
     * @param $clientId
     * @param $productId
     * @return bool
     */
    public function clientHasProduct($clientId, $productId)
    {
        return ! is_null(
            DB::table('client_product')
              ->where('client_id', $clientId)
              ->where('product_id', $productId)
              ->first()
        );
    }

Вы можете поместить это в свою модель пользователя / клиента или вы можете иметь его в клиенте и использовать его везде, где вам это нужно.

if ($this->clientRepository->clientHasProduct($clientId, $productId)
{
    return 'Awesome';
}

Но если вы уже определили отношение belongsToMany на клиентской модели красноречия, вы можете сделать это внутри своей клиентской модели, вместо этого:

    return ! is_null(
        $this->products()
             ->where('product_id', $productId)
             ->first()
    );
Jarek Tkaczyk

03.07.2014 08:13:14

методы @nielsiano будут работать, но они будут запрашивать БД для каждой пары пользователь/продукт, что, на мой взгляд, является пустой тратой времени.

Если вы не хотите загружать все связанные модели данных, то это то, что я сделал бы для одного пользователя:

// User model
protected $productIds = null;

public function getProductsIdsAttribute()
{
    if (is_null($this->productsIds) $this->loadProductsIds();

    return $this->productsIds;
}

public function loadProductsIds()
{
    $this->productsIds = DB::table($this->products()->getTable())
          ->where($this->products()->getForeignKey(), $this->getKey())
          ->lists($this->products()->getOtherKey());

    return $this;
}

public function hasProduct($id)
{
    return in_array($id, $this->productsIds);
}

Тогда вы можете просто сделать это:

$user = User::first();
$user->hasProduct($someId); // true / false

// or
Auth::user()->hasProduct($someId);

Выполняется только 1 запрос, после чего вы работаете с массивом.


Проще всего было бы использовать contains, как предложил @alexrussell.

Я думаю, что это вопрос предпочтений, поэтому, если ваше приложение не слишком большое и не требует большой оптимизации, вы можете выбрать то, с чем вам будет легче работать.

https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/24558722#comment38103724_24558722
Отличный ответ @deczo и удивительное использование встроенных помощников Laravel, чтобы сделать запрос динамичным в отношении ключей / таблиц - я сам стремлюсь к этому, но это выводит его на новый уровень! :Д
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/24558722#comment38104195_24558722
Спасибо, но все же нужно много играть с красноречием, чтобы узнать, какой из этих методов возвращает только ключ col_idа какой квалифицированную/префиксную table.col_id. К сожалению, красноречию довольно часто не хватает последовательности.
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/24558722#comment38106004_24558722
Да - я должен сказать, с максимальным уважением к Тейлору, чем больше вы вникаете в Laravel, тем больше вы находите раздражающих несоответствий и кода, который не слишком ясен (и без полезных комментариев / документации). Но эй, я же не могу сделать ничего лучше!
saggid

06.03.2015 08:27:14

Привет всем) мое решение этой проблемы: я создал собственный класс, расширенный из Eloquent, и расширяю все свои модели из него. В этом классе я написал эту простую функцию:

function have($relation_name, $id) {
    return (bool) $this->$relation_name()->where('id','=',$id)->count();
}

Для проверки существующего отношения необходимо написать что-то вроде:

if ($user->have('subscribes', 15)) {
    // do some things
}

Этот способ генерирует только число SELECT(...) запрос без получения реальных данных из таблиц.

ilvsx

29.03.2016 10:32:35

использование признака:

trait hasPivotTrait
{
    public function hasPivot($relation, $model)
    {
        return (bool) $this->{$relation}()->wherePivot($model->getForeignKey(), $model->{$model->getKeyName()})->count();
    }
}

.

if ($user->hasPivot('tags', $tag)){
    // do some things...
}
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/36278108#comment65836549_36278108
Это не решило мою проблему, но помогло мне встать на правильный путь, спасибо.
Mouagip

13.09.2016 02:42:08

Вопрос довольно старый, но это может помочь другим в поисках решения.:

$client = Client::find(1);
$exists = $client->products()->where('products.id', $productId)->exists();

Нет "расточительности", как в решении @alexrussell, и запрос также более эффективен.

https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/39469162#comment66277022_39469162
Я получаю ошибку SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias:когда я пытаюсь это сделать в своей модели :/
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/39469162#comment66291997_39469162
@George тогда попробуй where('products.id', $productId).
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/39469162#comment85390387_39469162
не думайте, что вам нужен псевдоним таблицы там, id достаточно. это определяется в соотношении продуктов. Чистейший раствор софар имхо.
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/39469162#comment85394693_39469162
@Johan вам нужен псевдоним, если, напримерclientтоже есть ID. Это довольно распространенное явление.
https://stackoverflow.com/questions/24555697/check-if-belongstomany-relation-exists-laravel/39469162#comment99642187_39469162
Это решение работает более стабильно. У меня была проблема, когда я перебирал слишком быстро с $client - > products - >>contains($product_id);
Alexey Mezenin

03.01.2018 10:25:24

Решение Алекса работает одно, но оно загрузит Clientмодель и все связанные Product.

1. Вам не нужно загружать модель клиента,вы можете просто использовать его идентификатор.

2. Вам также не нужно загружать в память все продукты, связанные с этим клиентом, как это делает Алекс.

3. Один SQL-запрос к БД.

whereHas()
Maksim Ivanov

12.11.2019 08:14:19

Чтобы проверить существование связи между двумя моделями, все, что нам нужно, - это один запрос к сводной таблице без каких-либо соединений.

Вы можете достичь этого с помощью встроенного newPivotStatementForId

daniel tamayo

18.02.2020 11:41:02

На это есть время но может быть я смогу кому то помочь

если($клиент->продукты()->найти($продукта->идентификатор)){ существует!! }

Следует отметить, что вы должны иметь модель продукта и клиента, я надеюсь, что это поможет,

Закрыть X