Связи сущностей
GraphQL запросы могут просматривать связанные объекты и их поля, поэтому с помощью одного запроса можно написать примерно следующее:
{
books
{
items {
id
title
authors {
items {
first_name
last_name
}
}
}
}
}
Для извлечения книг и их авторов.
Чтобы обеспечить эту возможность, построитель API данных должен знать, как два объекта связаны друг с другом. Раздел relationships
в файле конфигурации содержит необходимые метаданные для правильной и эффективной работы этой возможности.
Настройка связи
Независимо от того, какую базу данных вы используете с построителем API данных, необходимо явно сообщить построителю API данных, что объект связан с другим. Существует три типа связей, которые можно установить между двумя сущностями:
Связи «один ко многим»
Связь "один ко многим" позволяет объекту получить доступ к списку связанных объектов. Например, серия книг может разрешить доступ ко всем книгам этой серии:
{
series {
items {
name
books {
items {
title
}
}
}
}
}
Если есть внешние ключи, поддерживающие связь между двумя базовыми объектами базы данных, необходимо только сообщить конструктору API данных, что вы хотите предоставить такую связь. С помощью ИНТЕРФЕЙСА КОМАНДНОй строки DAB:
dab update Series --relationship books --target.entity Book --cardinality many
Обновление сущности series
, используемое в примере:
"Series": {
"source": "dbo.series",
...
"relationships": {
"books": {
"target.entity": "Book",
"cardinality": "many"
}
}
...
}
В элементе relationships
добавляется новый ключ: books
. Элемент определяет имя, которое используется для поля GraphQL для перехода от series
объекта к объекту, определенному target.entity
в , Book
в данном случае. Это означает, что в файле конфигурации должна быть сущность с именем Book
.
Свойство cardinality
сообщает построителю API данных, что в каждой серии может быть много книг, поэтому созданное поле GraphQL возвращает список элементов.
Это свойство все, что вам нужно. При запуске построитель API данных автоматически обнаруживает поля базы данных, которые необходимо использовать для поддержания определенной связи.
Если у вас нет ограничения внешнего ключа, поддерживающего связь с базой данных, построитель API данных не сможет автоматически определить, какие поля используются. Чтобы сообщить построителю API данных, какие поля связаны с двумя сущностями, необходимо указать их вручную. Их можно указать с помощью ИНТЕРФЕЙСА командной строки с помощью dab update
:
dab update Series --relationship books --target.entity Book --cardinality many --relationship.fields "id:series_id"
Параметр relationship.fields
позволяет определить, какие поля используются из обновляемой сущности (Series
), а какие — из целевой сущности (Book
) для подключения данных из одной сущности к другой.
В предыдущем примере id
поле базы данных сущности Series
сопоставляется с полем series_id
базы данных сущности Book
.
Конфигурация также содержит следующие сведения:
"Series": {
"source": "dbo.series",
...
"relationships": {
"books": {
"cardinality": "many",
"target.entity": "Book",
"source.fields": ["id"],
"target.fields": ["series_id"]
}
}
...
}
Связь "многие к одному"
Связь "многие ко многим" похожа на связь "один ко многим" с двумя основными отличиями:
- для
cardinality
задано значениеone
- Созданное поле GraphQL возвращает скаляр, а не список
После примеров серии книг, использовавшихся ранее, книга может находиться только в одной серии, поэтому связь создается с помощью следующей команды ИНТЕРФЕЙСА КОМАНДНОй строки DAB:
dab update Book --relationship series --target.entity Series --cardinality one
Которая создает эту конфигурацию:
"Book": {
"source": "dbo.books",
...
"relationships": {
"series": {
"target.entity": "Series",
"cardinality": "one"
}
}
}
Что, в свою очередь, позволяет GraphQL запрос, как в следующем примере:
{
books {
items {
id
title
series {
name
}
}
}
}
Где каждая книга возвращает также ряд, к которому она принадлежит.
Связь "многие ко многим"
Отношения "многие ко многим" можно рассматривать как пару связей "один ко многим" и "многие ко многим", работающих вместе. Автор, безусловно, может написать несколько книг (связь "один ко многим"), но также верно, что несколько авторов могут работать над одной книгой (связь "многие ко одному").
Построитель API данных поддерживает этот тип связи в собственном коде:
- Использование пары связей "один ко многим" и "многие к одному".
- Использование связывающего объекта.
Использование пары связей "один ко многим" и "многие к одному"
Одним из бизнес-требований, которое, скорее всего, будет отслеживание того, как роялти разделены между авторами книги. Для реализации такого требования требуется выделенная сущность, которая связывает автора, книга и назначенные роялти. Поэтому требуются три сущности:
authors
— для представления биографических сведений об авторах.books
, чтобы представлять данные книги, такие как название и международный стандартный номер книги (ISBN).books_authors
для представления данных, связанных как с книгой, так и с ее автором, например, процент роялти, который автор получает за определенную книгу.
Эти три сущности можно визуализировать на следующей схеме.
Как видно, существует две двунаправленные связи:
- Связь "один ко многим"/ "многие к одному" между
authors
иbooks_authors
- Связь "один ко многим"/ "многие к одному" между
books
иbooks_authors
Для корректной обработки такого сценария с помощью DAB достаточно создать связанные сущности и сопоставления в файле конфигурации. Предположим, Book
что сущность и Author
уже находятся в файле конфигурации:
dab add BookAuthor --source dbo.books_authors --permissions "anonymous:*"
Чтобы добавить новую сущность, выполните команду dab update
:
dab update Book --relationship authors --target.entity BookAuthor --cardinality many --relationship.fields "id:book_id"
dab update Author --relationship books --target.entity BookAuthor --cardinality many --relationship.fields "id:author_id"
Чтобы добавить связи к созданной BookAuthor
сущности, выполните dab update
еще раз:
dab update BookAuthor --relationship book --target.entity Book --cardinality one --relationship.fields "book_id:id"
dab update BookAuthor --relationship author --target.entity Author --cardinality one --relationship.fields "author_id:id"
Добавление связей из BookAuthor
сущностей Book
и Author
. С помощью предоставленной конфигурации DAB может обрабатывать вложенные запросы, как в следующем примере:
{
authors {
items {
first_name
last_name
books {
items {
book {
id
title
}
royalties_percentage
}
}
}
}
}
Где вы просите вернуть всех авторов, книгу они написали вместе со связанными роялти.
Использование связывающего объекта
Процесс, описанный в предыдущем разделе, отлично подходит для доступа ко всем сущностям, участвующим в связях "многие ко многим", через GraphQL. Этот сценарий не всегда так. Например, если вам не нужно отслеживать роялти, BookAuthor
сущность на самом деле не приносит никакой ценности для конечного пользователя. Сущность использовалась только для связанных книг с авторами. В реляционных базах данных связи "многие ко многим" создаются с помощью такой третьей таблицы, которая связывает таблицы, участвующие в связи "многие ко многим":
На схеме видно, что есть таблица с именем books_authors
, которая связывает авторов с их книгами, а книги с их авторами. Эта связываемая таблица не требуется предоставлять пользователю. Связывая таблица — это просто артефакт, позволяющий существовать связи "многие ко многим", но построитель API данных должен знать о ее существовании, чтобы правильно использовать ее.
ИНТЕРФЕЙС КОМАНДНОй строки DAB можно использовать для создания связи "многие ко многим", а также настройки объекта связывания (удалите все связи, созданные в предыдущем разделе, и начинайте только с Book
сущности и Author
без настроенной связи между ними).
dab update Book --relationship authors --target.entity Author --cardinality many --relationship.fields "id:id" --linking.object "dbo.books_authors" --linking.source.fields "book_id" --linking.target.fields "author_id"
При этом файл конфигурации JSON обновляется так, как в следующем примере:
"Book": {
"source": "dbo.books",
...
"relationships": {
"authors": {
"cardinality": "many",
"target.entity": "author",
"source.fields": [ "id" ],
"target.fields": [ "id" ],
"linking.object": "dbo.books_authors",
"linking.source.fields": [ "book_id" ],
"linking.target.fields": [ "author_id" ]
}
}
}
Конфигурация сообщает DAB, что вы хотите добавить authors
поле в Book
сущность, которая разрешает доступ авторам книги. authors
может иметь значение many
, поэтому список авторов возвращается, когда запрос GraphQL обращается к полюauthors
. Эта связь определяет способ перехода междукнигами и авторами: поля базы данных, используемые для перехода между книгами и их авторами, определяются в source.fields
для книги и в target.fields
для авторов аналогично связи "один ко многим" или "многие к одному", описанной ранее в этой статье.
Это отношение "многие ко многим", поэтому между двумя сущностями нет прямого соединения, поэтому linking.object
необходимо использовать . В примере таблица dbo.books_authors
базы данных используется в качестве связывающего объекта. То, как объект ссылки может подключать книги к авторам, определяется в свойствах linking.source.fields
и linking.target.fields
. Первый из них сообщает DAB о том, как исходная сущность — Book
— подключена к объекту liking, а вторая — о том, как связанный объект подключен к целевой Author
сущности в примере.
Чтобы понять, как используются предоставленные сведения, можно использовать следующий пример эквивалентного запроса:
select *
from dbo.books as b
inner join dbo.books_authors as ba on b.id = ba.book_id
inner join dbo.authors a on ba.author_id = a.id
С помощью предоставленной конфигурации DAB может понять GraphQL, как в следующем примере:
{
books {
items {
id
title
authors {
items {
first_name
last_name
}
}
}
}
}
Где вы хотите получить книги и их авторов.
Чтобы разрешить переход от Author
к Book
, можно применить те же принципы, обновив конфигурацию с помощью следующей команды:
dab update Author --relationship books --target.entity Book --cardinality many --relationship.fields "id:id" --linking.object "dbo.books_authors" --linking.source.fields "author_id" --linking.target.fields "book_id"
Определяет связь "многие ко многим" между сущностью Author
и сущностью Book
с использованием связующего объекта dbo.books_authors
в фоновом режиме.