7.9 KiB
7.9 KiB
Relacje między obiektami - Przewodnik
Spis treści
- Typy relacji
- Relacja jeden-do-wielu (master-detail)
- Relacja wiele-do-wielu
- Relacja do interfejsu
- Historia (wersjonowanie)
- Relacja zwrotna (self-reference)
Typy relacji
| Typ | Opis | W bazie danych | Przykład |
|---|---|---|---|
| Jeden-do-wielu | Dokument → Pozycje | FK (ID) | Faktura ma wiele pozycji |
| Wiele-do-wielu | Przez tabelę łączącą | 2x FK | Towar ↔ Kategorie |
| Interface'owa | Polimorficzna do wielu tabel | (tabela, ID) | IKontrahent → Osoba lub Firma |
| Historia | Wersjonowanie temporalne | FK + okres | Ceny towaru w czasie |
| Zwrotna | Do tej samej tabeli | FK (ID) | Kategoria nadrzędna |
Relacja jeden-do-wielu
Wzorzec: Dokument z pozycjami
<!-- TABELA NADRZĘDNA (master) -->
<table name="Dokument" tablename="Dokumenty" guided="Root">
<key name="WgNumeru" keyunique="true" keyprimary="true">
<keycol name="Numer"/>
</key>
<col name="Numer" type="string" length="30" required="true"/>
<col name="Data" type="date" required="true"/>
</table>
<!-- TABELA PODRZĘDNA (detail) -->
<table name="PozycjaDokumentu" tablename="PozycjeDok">
<col name="Dokument" type="Dokument"
required="true"
readonly="true"
keyprimary="true"
children="Pozycje"
delete="cascade"
relguided="inner"
relname="Pozycje dokumentu"
description="Dokument, do którego należy pozycja"/>
<col name="Lp" type="int" required="true" batchfield="false"/>
<col name="Opis" type="string" length="200"/>
</table>
Kluczowe atrybuty relacji podrzędnej
| Atrybut | Wartość | Znaczenie |
|---|---|---|
required="true" |
Pozycja musi mieć dokument | |
readonly="true" |
Nie można przenosić między dokumentami | |
keyprimary="true" |
Klucz główny zaczyna się od dokumentu | |
children="Pozycje" |
Nazwa kolekcji w dokumencie: dokument.Pozycje |
|
delete="cascade" |
Usunięcie dokumentu usuwa pozycje | |
relguided="inner" |
Wymagane dla tabel szczegółów (bez guided) |
Zasada relguided="inner"
Tabele bez atrybutu guided (tabele szczegółów) muszą mieć dokładnie jedną relację z relguided="inner". Wskazuje ona obiekt główny, którego szczegóły są opisywane.
Klucz złożony z Lp
<col name="Dokument" type="Dokument"
keyprimary="true" keyclass="Lp" keyclasscol="Lp"
children="Pozycje" delete="cascade">
<!-- keycol definiuje dodatkową kolumnę w kluczu -->
</col>
<col name="Lp" type="int" required="true"/>
Relacja wiele-do-wielu
Wzorzec: Tabela łącząca
<!-- TABELA ŁĄCZĄCA -->
<table name="TowarKategoria" tablename="TowaryKategorie">
<col name="Towar" type="Towar"
required="true"
keyprimary="true"
keyunique="true"
children="Kategorie"
delete="cascade"
relname="Kategorie towaru">
<keycol name="Kategoria"/>
</col>
<col name="Kategoria" type="Kategoria"
required="true"
children="Towary"
delete="cascade"
relname="Towary w kategorii">
<keycol name="Towar"/>
</col>
</table>
Wzajemne keycol
Element <keycol> w kolumnie relacji tworzy indeks złożony:
<col name="Towar" type="Towar" keyunique="true">
<keycol name="Kategoria"/> <!-- Indeks: (Towar, Kategoria) -->
</col>
<col name="Kategoria" type="Kategoria">
<keycol name="Towar"/> <!-- Indeks: (Kategoria, Towar) -->
</col>
Relacja do interfejsu (polimorficzna)
Relacja interface'owa pozwala na wskazanie obiektu z dowolnej tabeli implementującej dany interface. W bazie danych zapisywana jest para: (nazwa_tabeli, ID).
Deklaracja interfejsu
Interface musi być zadeklarowany w business.xml. Sama definicja interfejsu (metody, właściwości) jest w kodzie C#.
<!-- DEKLARACJA INTERFEJSU w business.xml -->
<interface name="IKontrahent"/>
<interface name="IPodmiotKasowy"/>
Wzorzec: Relacja interface'owa
<!-- TABELA Z RELACJĄ INTERFACE'OWĄ -->
<table name="Zamowienie" tablename="Zamowienia">
<!-- Typ to nazwa interfejsu - może wskazywać na Osobę, Firmę, lub inny obiekt implementujący IKontrahent -->
<col name="Kontrahent" type="IKontrahent"
required="true"
relname="Kontrahent zamówienia"
description="Może być osobą fizyczną lub firmą"/>
<!-- Relacja interface'owa do podmiotu kasowego -->
<col name="Platnik" type="IPodmiotKasowy"
relname="Płatnik zamówienia"/>
</table>
Różnica: relacja zwykła vs interface'owa
| Cecha | Relacja zwykła | Relacja interface'owa |
|---|---|---|
| Typ kolumny | NazwaTabeli |
INazwaInterface |
| W bazie danych | tylko ID |
(nazwa_tabeli, ID) |
| Wskazuje na | jedną konkretną tabelę | dowolną tabelę implementującą interface |
| Przykład | type="Kontrahent" |
type="IKontrahent" |
Popularne interfejsy enova365
| Interfejs | Opis |
|---|---|
IKontrahent |
Kontrahent (osoba/firma) |
IPodmiotKasowy |
Podmiot kasowy |
IRightsSource |
Źródło uprawnień |
IElementSlownika |
Element słownika |
IGuidedRow |
Wiersz z nawigacją |
Historia (wersjonowanie)
Wzorzec: Dane historyczne
<table name="CenaHistoria" tablename="CenyHistoria">
<col name="Towar" type="Towar"
required="true"
readonly="true"
keyprimary="true"
keyclass="History"
keyclasscol="Okres"
children="HistoriaCen"
delete="cascade"
relguided="inner"
relname="Historia cen towaru"/>
<col name="Okres" type="FromTo" required="true"
caption="Okres obowiązywania"/>
<col name="CenaNetto" type="currency"/>
<col name="CenaBrutto" type="currency"/>
</table>
Kluczowe atrybuty historii
| Atrybut | Wartość | Znaczenie |
|---|---|---|
keyclass="History" |
Klasa indeksu historycznego | |
keyclasscol="Okres" |
Kolumna z okresem (FromTo) |
Typ FromTo
Wbudowany typ dla okresów czasowych z polami From i To.
Relacja zwrotna
Wzorzec: Struktura hierarchiczna
<table name="Kategoria" tablename="Kategorie" guided="Root">
<key name="WgKodu" keyunique="true" keyprimary="true">
<keycol name="Kod"/>
</key>
<col name="Kod" type="string" length="50" required="true"/>
<col name="Nazwa" type="string" length="100"/>
<col name="Nadrzedna" type="Kategoria"
children="Podkategorie"
relname="Kategoria nadrzędna"
description="Kategoria nadrzędna w hierarchii"/>
</table>
Z poziomem zagnieżdżenia
<col name="Nadrzedna" type="Kategoria" children="Podkategorie">
<keycol name="Poziom"/>
</col>
<col name="Poziom" type="int" readonly="true"
description="Poziom w hierarchii (0 = root)"/>
Wzorce złożone
Relacja z dodatkowymi danymi
<table name="UdzialWProjekcie" tablename="UdzialyWProjektach">
<col name="Projekt" type="Projekt"
keyprimary="true" keyunique="true"
children="Udzialy" delete="cascade">
<keycol name="Pracownik"/>
</col>
<col name="Pracownik" type="Pracownik"
required="true"
children="Projekty" delete="cascade">
<keycol name="Projekt"/>
</col>
<!-- Dodatkowe dane relacji -->
<col name="Rola" type="RolaWProjekcie"/>
<col name="OdKiedy" type="date"/>
<col name="DoKiedy" type="date"/>
<col name="Stawka" type="currency"/>
</table>
Relacja z kaskadowym usuwaniem warunkowym
<col name="Kontrahent" type="Kontrahent"
delete="cascade"
children="Dokumenty"
relname="Dokumenty kontrahenta">
<!-- Weryfikator sprawdza warunki przed usunięciem -->
<verifier name="Dokument.KontrahentDeleteVerifier"/>
</col>