laravel отношения между таблицами

Laravel Framework Russian Community

Вступление

Ваши таблицы скорее всего как-то связаны с другими таблицами БД. Например, статья в блоге может иметь несколько комментариев, а заказ может быть с связан с оставившим его пользователем. Eloquent упрощает работу с такими отношениями. Laravel поддерживает несколько типов связей:

Определение отношений

Отношения Eloquent определяются при помощи методов в модели Eloquent. Т.к. связи (как и сами модели) по сути являются конструкторами запросов, определение связей в виде методов позволяет использовать мощный механизм сцепления методов в цепочку и построения запроса. Например:

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

Один к одному

Определение обратного отношения

Итак мы можем получить модель телефона ( Phone ) из модели пользователя ( User ). Давайте теперь определим связь на стороне телефона, что позволит нам иметь доступ к модели пользователя ( User ), владельцу телефона. Мы можем определить обратное отношение к hasOne при помощи метода belongsTo :

Если родительская модель не использует id в качестве первичного ключа, или вы хотите связать дочернею модель с родительской по другой колонке, можно передать третьим параметром в метод belongsTo имя ключа для связи:

Один ко многим

Тип связи «один ко многим» используется для определения таких отношений, в которых одна модель может иметь неограниченное количество других моделей. Например статья в блоге может иметь неограниченное количество комментариев. Как и любые другие отношения Eloquent, связь «один ко многим» определяется при помощи метода модели Eloquent:

И конечно, т.к. наши отношения являются по сути построителями запроса, вы можете строить цепь вызовов добавляя необходимые условия, после вызова метода comments :

Определение обратного отношения

Теперь, когда у нас есть метод для получения всех комментариев записи блога, давайте определим отношение для получения родительской записи из модели комментария. Для описания обратной связи hasMany служит метод belongsTo :

Теперь, когда отношение описано, мы можем получить родительский объект Post для Comment через «динамический атрибут» post :

Если родительская модель не использует id в качестве первичного ключа, или вы хотите связать дочернею модель с родительской по другой колонке, можно передать третьим параметром в метод belongsTo имя ключа для связи:

Многие ко многим

Когда отношение описано, мы можем получить роли пользователя через динамический атрибут roles :

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

Как упомянуто выше, имя связующей таблицы по умолчанию строится по именам моделей в алфавитном порядке. Однако его можно переопределить. Делается это при помощи второго параметра метода belongsToMany :

Определение обратного отношения

Для определения обратного отношения «многие ко многим» необходимо просто добавить такой же вызов метода belongsToMany но, со стороны другой модели. В продолжение нашего примера с ролями пользователя, определим метод users в модели Role :

Работа с данными связующих таблиц

Как вы уже знаете отношения типа «многие ко многим» требует дополнительную связующую таблицу. Eloquent позволяет работать с этой таблицей, что бывает весьма полезно. Предположим, что наш объект User имеет много ролей (объектов Role ). После того, как мы получили объект отношения, мы можем получить доступ к связующей таблице при помощи атрибута pivot у каждого из объектов:

По умолчанию, в объекте pivot будут присутствовать только ключи моделей. Если ваша связующая таблица содержит дополнительные атрибуты, их необходимо перечислить при описании отношения:

Фильтрация условий при помощи связующей таблицы

Вы можете фильтровать результаты, возвращенные отношением belongsToMany при помощи условий к связующей таблице:

Многие ко многим через посредника (Has Many Through)

Отношение «многие ко многим через посредника» предоставляет удобный способ для доступа к отдаленным отношениям через отношение-посредник. Например, Страна ( Country ) может иметь много блог-записей( Post ) через модель пользователя ( User ). В примере ниже показано, как легко можно получить все блог-посты для указанной страны. Давайте посмотрим на таблицы, необходимые для построения такой связи:

Теперь, когда ясна структура таблиц для этого отношения, давайте опишем его в модели Country :

Первый аргумент метода hasManyThrough является именем конечной модели, второй аргумент — модель-посредник.

Полиморфические отношения

Структура таблиц

Полиморфические отношения позволяют модели быть связанной с более, чем одной моделью. Например, пользователи приложений могут «лайкать» как посты так и комментарии к ним. Используя полиморфическую связь, вы можете использовать одну таблицу likes для обоих сценариев. Давайте для начала посмотрим на структуру таблиц, которая необходима для построения подобного отношения:

Структура модели

Теперь давайте рассмотрим определение такого рода отношений в модели:

Доступ к данным полиморфических отношений

У нас есть структура таблиц и модели, теперь можно обращаться к отношениям из моделей. Например, получить лайки поста можно при помощи динамического атрибута likes :

Переопределение полиморфических типов

Или можно задать строку, которая будет являться ключом модели:

«Карту превращений» ( morphMap ) можно зарегистрировать в AppServiceProvider или создать для этой цели отдельный сервис-провайдер.

Полиморфические отношения «многие ко многим»

Структура таблиц

Структура модели

Определение обратного отношения

Затем, в модели Tag необходимо задать метод для получения связанных моделей. В нашем случае определим методы posts и videos :

Доступ к данным отношения

После того, как база данных и модели определены, можно получить данные отношений из моделей. Например для получения всех тегов поста просто используйте динамический атрибут tags :

Запросы к отношениям

Так как все отношения Eloquent определяются в виде функций, вы можете получить инстанс отношения без исполнения запроса на получение данных. К тому же, все типы отношений Eloquent являются построителями запроса, что позволяет добавлять условия по цепочке вызовов до того, как произойдет сам SQL запрос.

Рассмотрим пример: представьте некий блог, в котором одной модели User может соответствовать много моделей Post :

Обратите внимание, что при запросе к отношению можно использовать любой из методов построения запроса!

Динамический атрибут или вызов метода

Если у вас нет необходимости добавлять дополнительные условия к получению данных отношений Eloquent читать отношение можно просто через динамический атрибут. Например, в нашем примере с пользователем User и постами Post мы можем получить все посты пользователя так:

Динамические атрибуты являются атрибутами «отложенной загрузки» («lazy loading»), это означает, что данные будут загружаться только при непосредственном обращении к атрибуту. Из-за этого разработчики часто используют жадную загрузку (eager loading) чтобы предварительно получить данные отношений, которые точно будут использоваться при обращении к текущей модели. «Жадная загрузка» позволяет существенно снизить количество SQL запросов, необходимых для получения отношений модели.

Проверка существования отношения

Также можно добавить оператор и указать число:

Можно организовать вложенность через «точку». Например, получить все посты у которых есть хотя бы один комментарий с голосом так:

Подсчет результатов

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

Жадная загрузка

Динамические атрибуты отношений являются атрибутами «отложенной загрузки» («lazy loading»), это означает, что данные будут загружаться только при непосредственном обращении к атрибуту. Однако, Eloquent дает возможность «жадной загрузки» («eager load») отношений во время получения данных самой модели. Жадная загрузка снимает проблему N + 1 запросов. Для того чтобы понять, что такое проблема N + 1 запросов, рассмотрим модель Book связанную с моделью Author :

Теперь давайте получим все книги вместе с авторами:

Этот цикл произведет один запрос к таблице с книгами, затем еще по запросу на каждую книгу для получения автора. И, если у нас 25 книг, цикл сделает 26 запросов: 1 для книг, и 25 для получения автора каждой книги.

К счастью, у нас есть «жадная загрузка», которая сведет все к 2 запросам. Какое отношение загрузить «жадно» можно указать при помощи метода with :

Для данной операции выполнится всего два запроса:

Жадная загрузка нескольких отношений

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

Вложенная жадная загрузка

Для жадной загрузки вложенных отношений используйте синтаксис с «точкой». Для примера давайте загрузим книги с авторами и их персональными данными одним выражением Eloquent:

Условия при жадной загрузке

Иногда может понадобиться жадная загрузка отношения, но с дополнительным условием на выборку связанных данных Вот пример:

Отложенная жадная загрузка

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

Если вам необходимо добавить свои условия на выборку отношений, передайте Closure в метод load :

Добавление связанных моделей

Метод Save (сохранение)

Если необходимо добавить несколько связанных моделей, используйте метод saveMany :

Метод Save и отношение «многие ко многим»

При работе с отношениям типа «многие ко многим» метод save принимает массив дополнительных атрибутов связующей таблицы в качестве второго параметра:

Метод Create (создание)

Обновление отношения «Belongs To»

Отношения многие-ко-многим

Связывание / Отвязывание

Для удобства работы с отношениями типа «многие-ко-многим» Eloquent предоставляет несколько дополнительных методов. Давайте предположим, что у нас есть пользователь, который имеет несколько ролей, роль в свою очередь может относиться ко многим пользователям. Для того, чтобы связать роль с пользователем путем добавления записи в связующую таблицу, используйте метод attach :

При связывании можно также передать массив с дополнительными данными для связующей таблицы:

В целях удобства, методы attach и detach также принимают на вход массивы ID:

Обновление записи связующей таблицы

Если необходимо обновить данные существующей записи связующей таблицы, используйте метод updateExistingPivot :

Синхронизация

Посмотрите также в сторону метода sync для создания связей «многие ко многим». Метод sync принимает массив ID для связующей таблицы. Те ID которые отсутствуют в масиве будут удалены из таблицы связей. Таким образом в результате выполнения метода записи в связующей таблице будут соответствовать массиву, который в него передали:

Вместе с ID можно передать также дополнительные данные для связующей таблицы:

Обновление родительских таймстемпов

Источник

Laravel Framework Russian Community

Пролог

Начало работы

Основы архитектуры

Основы

Фронтенд

Безопасность

Копаем глубже

База данных

Eloquent ORM

Тестирование

Официальные пакеты

Eloquent: Отношения

Введение

Ваши таблицы скорее всего как-то связаны с другими таблицами БД. Например, статья в блоге может иметь много комментариев, а заказ может быть связан с оставившим его пользователем. Eloquent упрощает работу и управление такими отношениями. Laravel поддерживает следующие типы связей:

Определение отношений

Eloquent отношения определены как функции в ваших классах модели Eloquent. С отношениями можно работать используя мощный конструктор запросов, который обеспечивает сцепку методов и возможность добавлять запросы. Например, мы можем прицепить дополнительный запрос к отношениям posts пользователя:

Но прежде чем погрузиться в использование отношений, давайте узнаем, чем они отличаются друг от друга.

Названия отношений в модели не должны совпадать с названиями её свойств (атрибутов).

Один к одному

Первый параметр, передаваемый hasOne — имя связанной модели. Как только отношение установлено, вы можете получить к нему доступ через динамические свойства Eloquent. Динамические свойства позволяют вам получить доступ к функциям отношений, если бы они были свойствами модели:

Создание обратного отношения

Модели по умолчанию

Чтобы заполнить модель по умолчанию атрибутами, вы можете передать массив или функцию замыкания методу withDefault :

Один ко многим

Отношение «один ко многим» используется для определения отношений, где одна модель владеет некоторым количеством других моделей. Примером отношения «один ко многим» является статья в блоге, которая имеет «много» комментариев. Как и другие отношения Eloquent вы можете смоделировать это отношение таким образом:

Вы можете добавлять дополнительные условия к тем комментариям, которые получены вызовом метода comments :

Один ко многим (обратное отношение)

Многие ко многим

Структура таблиц

Структура модели

Для отношения «многие ко многим», нужно написать метод, возвращающий результат метода belongsToMany :

Теперь мы можем получить роли пользователя через динамическое свойство roles :

Как уже упоминалось ранее, чтобы определить имя для таблицы присоединения отношений, Eloquent соединит два названия взаимосвязанных моделей в алфавитном порядке. Тем не менее, вы можете переопределить имя, передав второй параметр методу belongsToMany :

Определение обратного отношения

Чтобы определить обратное отношение «многие-ко-многим», просто поместите другой вызов belongsToMany на вашу модель. Чтобы продолжить пример с ролями пользователя, давайте определим метод users для модели Role :

Получение промежуточных столбцов таблицы

Настройка имёни сводной таблицы

Теперь вы можете обращаться к сводной таблице по имени subscription :

Фильтрация отношений через столбцы промежуточной таблицы

Определение пользовательских моделей промежуточных таблиц

Вы можете комбинировать using и withPivot для получения столбцов из промежуточной таблицы. Например, так можно получить created_by и updated_by из RoleUser :

Пользовательские промежуточные модели и автоинкремент

Один к одному через

Отношения «Один к одному через» связывают модели через одну промежуточную связь.

Например, если у каждого поставщика есть один пользователь, и каждый пользователь связан с одной записью истории пользователя, то модель поставщика может получить доступ к истории пользователя через пользователя. Структура БД:

Вы также можете задать явно названия ключей, при помощи которых осуществляются связи:

Ко многим через

Теперь, когда мы рассмотрели структуру таблицы для отношений, давайте определим отношения для модели Country :

Вы также можете задать явно названия ключей, при помощи которых осуществляются связи:

Полиформные отношения

Полиморфные отношения позволяют модели быть связанной с более чем одной моделью, используя одну и ту же ассоциацию.

Один к одному (полиморфное отношение)

Структура таблиц

Полиморфные отношения позволяют модели быть связанной с более чем одной моделью. Например, у нас используются изображения в качестве шапки для постов и профайлов пользователей. Чтобы не делать две отдельные таблицы images vs можем сделать одну с полиморфной связью к постам и пользователям. Структура таблиц будет такой:

Структура модели

Модели будут выглядеть так:

Получение отношения

Получить изображение, привязанное к посту можно следующим обычным способом:

Также вы можете использовать имя полиморфного отношения, заданного в модели:

Один ко многим (полиморфное отношение)

Структура таблиц

Полиморфное отношение «один ко многим» аналогично простому отношению «один ко многим». Однако целевая модель может принадлежать к нескольким типам моделей по одной ассоциации. Например, представьте, что пользователи вашего приложения могут комментировать и посты и видео. Используя полиморфные связи, вы можете использовать одну таблицу comments для обоих этих сценариев. Структура таблиц будет следующая:

Столбец commentable_id содержит id поста или видео, а commentable_type — имя класса модели, т.е. поста или видео.

Структура модели

Теперь давайте рассмотрим, какие определения для модели нам нужны, чтобы построить её отношения:

Получение отношений

После определения моделей и таблиц вы можете получить доступ к отношениям через модели. Например, чтобы получить все комментарии статьи, используйте динамическое свойство comments :

Многие ко многим (полиморфное отношение)

Структура таблиц

Структура модели

Обе модели Post и Video будут иметь связь morphToMany в базовом классе Eloquent через метод tags :

Определение обратного отношения

Теперь для модели Tag вы можете определить метод для каждой из моделей отношения. Для нашего примера мы определим метод posts и метод videos :

Получение отношения

Как только ваша таблица и модели определены, вы можете получить доступ к отношениям через свои модели. Например, чтобы получить доступ ко всем тегам для сообщения, вы можете просто использовать динамическое свойство tags :

Пользовательские полиморфные типы

Вы можете зарегистрировать morphMap в функции boot в своём AppServiceProvider или создать отдельный сервис-провайдер.

Запросы к отношениям

Допустим, у вас модель User имеет множество Post :

Вы можете использовать на отношениях любой из методов конструктора запросов.

Применение ИЛИ в отношениях

Этот запрос даст следующий SQL, что может быть не тем, что вы ожидаете получить:

В большинстве случаев для использования ИЛИ вместе с И вас следует объединять запросы в группы

Данная конструкция интерпретируется в следующий SQL-запрос:

Отношения: методы или свойства

Динамические свойства поддерживают «отложенную (ленивую) загрузку». Это означает, что данные загружаются из БД только в момент обращения к отношениям. Иногда применяют жадную загрузку, чтобы предварительно загрузить отношения, для которых известно, что они точно понадобятся. Жадная загрузка обеспечивает значительное сокращение SQL-запросов, если вы берёте не одну модель, а несколько.

Проверка существования связей при выборке

При чтении отношений модели вам может быть нужно ограничить результаты в зависимости от существования отношения. Например, вы хотите получить все публикации в блоге, имеющие хотя бы один комментарий. Для этого можно использовать метод has :

Вы также можете указать оператора и число, чтобы еще больше настроить запрос:

Можно конструировать вложенные операторы has с записи через точку. Например, вы можете получить все публикации, которые имеют хотя бы один комментарий и голос:

Выборка по отсутствию отношения

При получении записей модели бывает необходимо ограничить результаты выборки на основе отсутствия отношения. Например, если вы хотите получить все статьи, у которых нет комментариев. Для этого передайте имя отношения в метод doesntHave :

Для запроса к вложенным отношениям можно использовать dot-нотацию. Например, запросим все посты с коментариями незабаненных авторов:

Выборка по полиморфным отношениям

Чтобы проверить, существуют ли результаты по полиморфному отношению, используйте whereHasMorph :

Вместо того, чтобы передавать массив возможных полиморфных моделей, Вы можете использовать * и позволить Ларавелу получить все возможные полиморфные типы из базы данных. Для выполнения этой операции Ларавел выполнит дополнительный запрос:

Подсчёт моделей в отношении

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

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

Жадная загрузка

Теперь давайте получим все книги и их авторов:

Этот цикл выполнит 1 запрос, чтобы получить все книги, затем выполнится по одному запросу для каждой книги, чтобы получить автора. Так, если бы у нас было 25 книг, этот код выполнил бы 26 запросов: 1 для исходной книги и 25 дополнительных запросов, чтобы получить автора каждой книги.

К счастью, мы можем использовать жадную загрузку, чтобы уменьшить эту работу всего до 2 запросов. При запросах вы можете определить, какие отношения должны быть жадно загружены с использованием метода with :

Для данной операции будут выполнены только два запроса:

Жадная загрузка нескольких отношений

В with можно указать массив с именами отношений для жадной загрузки:

Вложенная жадная загрузка

Вложенная жадная загрузка для полиморфных отношений

Используя эти определения моделей и связи, мы можем получить экземпляры моделей ActivityFeed и загрузить все parentable модели и их соответствующие вложенные связи:

Жадная загрузка указанных столбцов в модели отношения

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

При использовании этой функции, вы всегда должны включать id и внешние ключи (например, user_id ) в список столбцов, которые вы хотите получить.

Жадная загрузка по умолчанию

Для того, чтобы модель всегда подгружала указанные отношения, добавьте их в protected свойство with :

В случае, когда вам понадобится отключить дефолтную жадную загрузку, используйте метод without :

Условия для жадных загрузок

Иногда вам может понадобиться указать дополнительные условия для запроса на загрузку. Например:

Также вы можете вызвать другие методы конструктора запросов для дополнительной настройки жадной загрузки:

Методы limit и take в данном случае не могут быть использованы.

Отложенная жадная загрузка

Если вам нужно установить дополнительные условия, вместо имени отношения вы можете передать массив с функцией, где укажите нужные условия:

Для того, чтобы загрузить отношения, если они ещё не загружены, используйте loadMissing :

Отложенная жадная загрузка для полиморфных отношений

Этот метод принимает имя отношения morphTo в качестве первого аргумента, а массив моделей/пар отношений в качестве второго аргумента. Для иллюстрации этого метода рассмотрим следующую модель:

Используя эти определения моделей и связи, мы можем получить экземпляры моделей ActivityFeed и загрузить все parentable модели и их соответствующие вложенные отношения:

Вставка и изменение связанных моделей

Метод Save

Если вам нужно добавить сразу несколько моделей, используйте метод saveMany :

Рекурсивное сохранение моделей и отношений

Если Вы хотите сохранить вашу модель и все связанные с ней отношения, вы можете использовать метод push :

Метод Create

Перед использованием метода create освежите в памяти документацию по массовому присваиванию атрибутов.

Вы можете использовать метод createMany для создания и добавления нескольких моделей:

Отношения «Принадлежит к»

Default Models

Отношения многие-ко-многим

Присоединение / Отсоединение

Давайте предположим, что у пользователя может быть много ролей, и у роли может быть много пользователей. Чтобы присоединить роль к пользователю вставкой записи в промежуточную связующую таблицу, которая присоединяется к моделям, используйте метод attach :

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

Для удобства attach и detach также принимают массивы id:

Синхронизация ассоциаций

Также вы можете передать дополнительные значения промежуточной таблицы с массивом ID:

Если вы не хотите отделять существующие ID, используйте метод syncWithoutDetaching :

Переключение ассоциаций

Сохранение дополнительных данных в связующей таблице

При работе с отношением многие-ко-многим метод save принимает вторым аргументом массив дополнительных атрибутов промежуточной таблицы:

Изменение записи в связующей таблице

Установка меток времени родителям

Источник

Понравилась статья? Поделить с друзьями:
Добавить комментарий
  • Как сделать успешный бизнес на ритуальных услугах
  • Выездной кейтеринг в России
  • Риски бизнеса: без чего не обойтись на пути к успеху
  • lapin house интернет магазин школьная форма
  • landing card uk образец заполнения