278 lines
7.9 KiB
Markdown
278 lines
7.9 KiB
Markdown
# Relacje między obiektami - Przewodnik
|
|
|
|
## Spis treści
|
|
|
|
1. [Typy relacji](#typy-relacji)
|
|
2. [Relacja jeden-do-wielu (master-detail)](#relacja-jeden-do-wielu)
|
|
3. [Relacja wiele-do-wielu](#relacja-wiele-do-wielu)
|
|
4. [Relacja do interfejsu](#relacja-do-interfejsu)
|
|
5. [Historia (wersjonowanie)](#historia-wersjonowanie)
|
|
6. [Relacja zwrotna (self-reference)](#relacja-zwrotna)
|
|
|
|
---
|
|
|
|
## 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
|
|
|
|
```xml
|
|
<!-- 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
|
|
|
|
```xml
|
|
<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
|
|
|
|
```xml
|
|
<!-- 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:
|
|
|
|
```xml
|
|
<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#.
|
|
|
|
```xml
|
|
<!-- DEKLARACJA INTERFEJSU w business.xml -->
|
|
<interface name="IKontrahent"/>
|
|
<interface name="IPodmiotKasowy"/>
|
|
```
|
|
|
|
### Wzorzec: Relacja interface'owa
|
|
|
|
```xml
|
|
<!-- 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
|
|
|
|
```xml
|
|
<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
|
|
|
|
```xml
|
|
<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
|
|
|
|
```xml
|
|
<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
|
|
|
|
```xml
|
|
<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
|
|
|
|
```xml
|
|
<col name="Kontrahent" type="Kontrahent"
|
|
delete="cascade"
|
|
children="Dokumenty"
|
|
relname="Dokumenty kontrahenta">
|
|
<!-- Weryfikator sprawdza warunki przed usunięciem -->
|
|
<verifier name="Dokument.KontrahentDeleteVerifier"/>
|
|
</col>
|
|
```
|