Files
2025-12-26 22:22:34 +01:00

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>
```