Udostępnij za pośrednictwem


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.entityBook , 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_idBook 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 na one
  • 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.

Diagram przedstawiający relację wiele-do-wielu między autorami, books_authors i książkami.

Jak widać, istnieją dwie relacje dwukierunkowe:

  • Relacja jeden-do-wielu/wiele-do-jednego między authors i books_authors
  • Relacja jeden-do-wielu/wiele-do-jednego między books i books_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:

Diagram przedstawiający kolejną relację wiele-do-wielu między autorami, books_authors i książkami.

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.