Relacje jednostek
Zapytania GraphQL mogą przechodzić przez powiązane obiekty i ich pola, dzięki czemu można napisać tylko jedno zapytanie, takie jak:
{
books
{
items {
id
title
authors {
items {
first_name
last_name
}
}
}
}
}
Aby pobrać książki i ich autorów.
Aby umożliwić działanie tej możliwości, konstruktor interfejsu API danych musi wiedzieć, jak te dwa obiekty są ze sobą powiązane. Sekcja relationships
w pliku konfiguracji zawiera metadane niezbędne do poprawnego i wydajnego działania tej możliwości.
Konfigurowanie relacji
Niezależnie od używanej bazy danych z konstruktorem interfejsu API danych musisz jawnie poinformować konstruktora interfejsu API danych, że obiekt jest powiązany z innym. Istnieją trzy typy relacji, które można ustanowić między dwiema jednostkami:
Relacja jeden do wielu
Relacja jeden do wielu umożliwia obiektowi dostęp do listy powiązanych obiektów. Na przykład seria książek może zezwalać na dostęp do wszystkich książek z tej serii:
{
series {
items {
name
books {
items {
title
}
}
}
}
}
Jeśli istnieją klucze obce obsługujące relację między dwoma bazowymi obiektami bazy danych, musisz tylko poinformować konstruktora interfejsu API danych, że chcesz uwidocznić taką relację. Za pomocą interfejsu wiersza polecenia języka DAB:
dab update Series --relationship books --target.entity Book --cardinality many
Które aktualizuje jednostkę series
— używane w przykładzie:
"Series": {
"source": "dbo.series",
...
"relationships": {
"books": {
"target.entity": "Book",
"cardinality": "many"
}
}
...
}
Nowy klucz jest dodawany w elemecie relationships
: books
. Element definiuje nazwę używaną dla pola GraphQL, aby przechodzić z series
obiektu do obiektu zdefiniowanego w obiekcie target.entity
Book
, w tym przypadku. Oznacza to, że w pliku konfiguracji musi istnieć jednostka o nazwie Book
.
Właściwość cardinality
informuje konstruktora interfejsu API danych, że w każdej serii może znajdować się wiele książek, dlatego utworzone pole GraphQL zwraca listę elementów.
Ta właściwość to wszystko, czego potrzebujesz. Podczas uruchamiania konstruktor interfejsu API danych automatycznie wykrywa pola bazy danych, które muszą być używane do utrzymania zdefiniowanej relacji.
Jeśli nie masz ograniczenia klucza obcego utrzymującego relację bazy danych, konstruktor interfejsu API danych nie może ustalić automatycznie, jakie pola są używane. Aby poinformować konstruktora interfejsu API danych, jakie pola odnoszą się do dwóch jednostek, należy określić je ręcznie. Można je określić za pomocą interfejsu wiersza polecenia przy użyciu polecenia dab update
:
dab update Series --relationship books --target.entity Book --cardinality many --relationship.fields "id:series_id"
Opcja relationship.fields
umożliwia zdefiniowanie pól używanych z aktualizowanej jednostki (Series
) i pól używanych z jednostki docelowej (Book
), aby połączyć dane z jednej jednostki z drugiej.
W poprzednim przykładzie id
pole Series
bazy danych jednostki jest zgodne z polem series_id
Book
bazy danych jednostki.
Konfiguracja zawiera również następujące informacje:
"Series": {
"source": "dbo.series",
...
"relationships": {
"books": {
"cardinality": "many",
"target.entity": "Book",
"source.fields": ["id"],
"target.fields": ["series_id"]
}
}
...
}
Relacja wiele do jednego
Relacja wiele do jednego jest podobna do relacji jeden do wielu z dwoma ważnymi różnicami:
- parametr
cardinality
jest ustawiony naone
- utworzone pole GraphQL zwraca skalarną, a nie listę
Po przykładach z serii książek używanych wcześniej książka może znajdować się tylko w jednej serii, więc relacja jest tworzona przy użyciu następującego polecenia interfejsu wiersza polecenia języka DAB:
dab update Book --relationship series --target.entity Series --cardinality one
Która generuje tę konfigurację:
"Book": {
"source": "dbo.books",
...
"relationships": {
"series": {
"target.entity": "Series",
"cardinality": "one"
}
}
}
Co z kolei umożliwia wykonywanie zapytań GraphQL w następujący sposób:
{
books {
items {
id
title
series {
name
}
}
}
}
Gdzie każda książka zwraca również serię, do której należy.
Relacja wiele do wielu
Wiele do wielu relacji można postrzegać jako parę relacji jeden do wielu i wiele do jednego, które współpracują ze sobą. Autor z pewnością może napisać więcej niż jedną książkę (relację jeden do wielu), ale jest również prawdą, że więcej niż jeden autor może pracować nad tą samą książką (relacja wiele do jednego).
Konstruktor interfejsu API danych obsługuje ten typ relacji natywnie:
- Używanie pary relacji jeden-do-wielu/wiele-do-jednego.
- Używanie obiektu łączącego.
Używanie pary relacji jeden-do-wielu/wiele-do-jednego
Jednym z wymagań biznesowych, które prawdopodobnie będą istnieć, aby śledzić, jak tantiemy są podzielone między autorów książki. Aby zaimplementować takie wymaganie, potrzebna jest dedykowana jednostka łącząca autora, książka i przypisane tantiemy. W związku z tym potrzebne są trzy jednostki:
authors
, aby reprezentować szczegóły biograficzne autorów.books
, do reprezentowania danych książki, takich jak tytuł i numer standardowa książki (ISBN).books_authors
aby reprezentować dane powiązane zarówno z książką, jak i jej autorem, na przykład procent opłat licencyjnych, które autor otrzymuje dla określonej książki.
Trzy jednostki można wizualizować za pomocą poniższego diagramu.
Jak widać, istnieją dwie relacje dwukierunkowe:
- Relacja jeden-do-wielu/wiele-do-jednego między
authors
ibooks_authors
- Relacja jeden-do-wielu/wiele-do-jednego między
books
ibooks_authors
Aby obsłużyć taki scenariusz w sposób bezproblemowy przy użyciu języka DAB, potrzebne jest utworzenie powiązanych jednostek i mapowań w pliku konfiguracji. Zakładając, że jednostka Book
i Author
jest już w pliku konfiguracji:
dab add BookAuthor --source dbo.books_authors --permissions "anonymous:*"
Aby dodać nową jednostkę, uruchom polecenie 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"
Aby dodać relacje do nowo utworzonej BookAuthor
jednostki, uruchom dab update
ponownie polecenie:
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"
Aby dodać relacje z BookAuthor
do Book
i jednostek Author
. W przypadku podanej konfiguracji daB można obsługiwać zagnieżdżone zapytania, takie jak w tym przykładzie:
{
authors {
items {
first_name
last_name
books {
items {
book {
id
title
}
royalties_percentage
}
}
}
}
}
Gdzie prosisz o powrót wszystkich autorów, książka, którą napisali wraz z powiązanymi tantiemami.
Używanie obiektu łączącego
Proces opisany w poprzedniej sekcji działa świetnie, jeśli wszystkie jednostki zaangażowane w relacje wiele-do-wielu muszą być dostępne za pośrednictwem programu GraphQL. Ten scenariusz nie zawsze jest w tym przypadku. Jeśli na przykład nie musisz śledzić opłat licencyjnych, BookAuthor
jednostka nie przynosi żadnej wartości użytkownikowi końcowemu. Jednostka była używana tylko do skojarzonych książek ze swoimi autorami. W relacyjnych bazach danych relacje Wiele do wielu są tworzone przy użyciu takiej trzeciej tabeli, która łączy tabele biorące udział w relacji wiele-do-wielu:
Na diagramie widać, że istnieje tabela o nazwie books_authors
, która łączy autorów ze swoimi książkami i książkami ze swoimi autorami. Ta tabela łączenia nie musi być widoczna dla użytkownika końcowego. Tabela łączenia jest tylko artefaktem umożliwiającym istnienie relacji wiele-do-wielu, ale konstruktor interfejsu API danych musi znać jego istnienie, aby prawidłowo go używać.
Interfejs wiersza polecenia języka DAB może służyć do tworzenia relacji wiele-do-wielu, a także konfigurowania obiektu łączącego (upewnij się, że wszystkie relacje utworzone w poprzedniej sekcji zostały usunięte i zaczynają się tylko od Book
jednostki i Author
bez skonfigurowanej relacji między nimi):
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"
Który aktualizuje plik konfiguracji JSON tak, aby był podobny do następującego przykładu:
"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" ]
}
}
}
Konfiguracja informuje daB, że chcesz dodać authors
pole w Book
jednostce, która umożliwia dostęp do autorów książki. authors
może to być many
, więc lista autorów jest zwracana, gdy zapytanie GraphQL uzyskuje authors
dostęp do pola. Ta relacja definiuje sposób przechodzenia z książek do autorów: pola bazy danych używane do przechodzenia z książek do ich autorów są zdefiniowane w source.fields
książce, a także w target.fields
przypadku autorów, podobnie jak relacja jeden do wielu lub wiele do jednego opisana wcześniej w tym artykule.
Ta relacja jest relacją wiele-do-wielu, więc nie ma bezpośredniego połączenia między dwiema jednostkami i dlatego linking.object
należy użyć tej relacji. W przykładzie tabela dbo.books_authors
bazy danych jest używana jako obiekt łączący. Sposób łączenia obiektu umożliwia łączenie książek ze swoimi autorami w właściwościach linking.source.fields
i linking.target.fields
. Pierwszy informuje daB, w jaki sposób jednostka źródłowa — Book
jest połączona z obiektem lubijącym, a druga — jak obiekt łączący jest połączony z jednostką Author
docelową w przykładzie.
Aby zrozumieć, w jaki sposób są używane podane informacje, możesz użyć tego przykładowego równoważnego zapytania:
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
W przypadku podanej konfiguracji daB można zrozumieć język GraphQL w następujący sposób:
{
books {
items {
id
title
authors {
items {
first_name
last_name
}
}
}
}
}
Gdzie chcesz uzyskać książki i ich autorów.
Aby zezwolić na nawigację z Author
do Book
, można zastosować te same zasady, aktualizując konfigurację przy użyciu następującego polecenia:
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"
Definiuje relację wiele-do-wielu między Author
jednostką a Book
jednostką przy użyciu obiektu dbo.books_authors
łączącego w tle.