Files
2026-05-19 11:27:12 +02:00

471 lines
14 KiB
Markdown

# Przykłady kodu - Podstawowe klasy ORM
Praktyczne przykłady użycia podstawowych klas logiki biznesowej enova365/Soneta.
## Spis treści
- [Ważne zasady](#ważne-zasady) - thread-safety, transakcje, mieszanie sesji
- [Dostęp do danych](#dostęp-do-danych) - iteracja po kluczach, wyszukiwanie, filtrowanie
- [Tworzenie obiektów](#tworzenie-obiektów) - AddRow, walidacja, AddingRow
- [Modyfikacja obiektów](#modyfikacja-obiektów)
- [Usuwanie obiektów](#usuwanie-obiektów)
- [Praca z kontekstem](#praca-z-kontekstem) → szczegółowo w [context.md](context.md)
- [Praca z GuidedRow](#praca-z-guidedrow) → szczegółowo w [datapack-guidedrow.md](datapack-guidedrow.md)
- [Dane konfiguracyjne vs operacyjne](#dane-konfiguracyjne-vs-operacyjne) - `ExecuteConfig`
- [Pełny przykład - import towarów](#pełny-przykład---import-towarów)
- [Obsługa błędów](#obsługa-błędów) - try/catch wokół transakcji
## Ważne zasady
Ten plik zakłada znajomość fundamentów — przed sięgnięciem po przykłady upewnij się, że są jasne:
- **Thread-safety** (`Session`/`Row`/`Table`/`Module`/`Context` są single-threaded; `BusApplication`/`Database`/`Login` można współdzielić) — patrz [session-login.md](session-login.md).
- **Transakcje biznesowe** — każda zmiana obiektu (dodanie, modyfikacja property, kasowanie) wymaga otwartej transakcji `session.Logout(editMode: true)` zakończonej `Commit()`; zapis do bazy przez `session.Save()` poza transakcją. Szczegóły, w tym typy sesji, `CommitUI()` i optimistic locking — patrz [session-login.md](session-login.md).
- **Bezpieczny kod** — przy nowym kodzie i review weryfikuj reguły z [safe-code.md](safe-code.md).
### Extension methods dla modułów
Dostęp do modułów przez extension methods:
```csharp
var tm = session.GetTowary();
var hm = session.GetHandel();
var crm = session.GetCRM();
var kadry = session.GetKadry();
var bm = session.GetBusiness();
```
## Dostęp do danych
### Odczyt listy towarów
```csharp
using Soneta.Business;
using Soneta.Towary;
public void WyswietlTowary(Login login)
{
// Sesja tylko do odczytu
using (var session = login.CreateSession(true, false, "OdczytTowarow"))
{
var tm = session.GetTowary(); // Extension method
// Iteracja po kluczu podstawowym (WgKodu)
foreach (Towar t in tm.Towary.WgKodu)
{
Console.WriteLine($"{t.Kod}: {t.Nazwa}");
}
}
}
```
### Wyszukiwanie po kluczu
```csharp
public Towar ZnajdzTowar(Session session, string kod)
{
var tm = session.GetTowary();
// Wyszukiwanie po kluczu unikalnym
return tm.Towary.WgKodu[kod];
}
```
### Iteracja z filtrowaniem
```csharp
public void WyswietlAktywneTowary(Session session)
{
var tm = session.GetTowary();
foreach (Towar t in tm.Towary.WgKodu)
{
// Filtrowanie w kodzie
if (t.Typ == TypTowaru.Towar)
{
Console.WriteLine(t.Nazwa);
}
}
}
```
## Tworzenie obiektów
### Dodawanie nowego towaru
```csharp
public void DodajTowar(Login login)
{
// Sesja edycyjna
using (var session = login.CreateSession(false, false, "DodawanieTowaru"))
{
var tm = session.GetTowary();
// Transakcja biznesowa - wymagana!
using (var transaction = session.Logout(editMode: true))
{
// Utworzenie nowego obiektu
var towar = new Towar();
// Dodanie do tabeli (zmiana stanu na Added)
tm.Towary.AddRow(towar);
// Ustawienie właściwości
towar.Kod = "NOWY001";
towar.Nazwa = "Nowy towar";
towar.Typ = TypTowaru.Towar;
transaction.Commit();
}
// Zapisanie do bazy
session.Save();
}
}
```
### Dodawanie dokumentu z pozycjami
```csharp
public void UtworzFakture(Login login, Kontrahent kontrahentZInnejSesji,
List<(Towar towar, int ilosc)> pozycjeZInnejSesji)
{
using (var session = login.CreateSession(false, false, "TworzenieFaktury"))
{
var hm = session.GetHandel();
// WAŻNE: Obiekty z innej sesji trzeba doczytać w bieżącej sesji!
var kontrahent = session.Get(kontrahentZInnejSesji);
// Cała operacja w jednej transakcji
using (var transaction = session.Logout(editMode: true))
{
// Utworzenie nagłówka dokumentu
var faktura = new DokumentHandlowy();
hm.DokHandlowe.AddRow(faktura);
faktura.Definicja = hm.DefDokHandlowe.WgSymbolu["FV"];
faktura.Kontrahent = kontrahent;
faktura.Data = Date.Today;
// Dodanie pozycji
int lp = 1;
foreach (var (towarZInnejSesji, ilosc) in pozycjeZInnejSesji)
{
// Doczytaj towar w bieżącej sesji
var towar = session.Get(towarZInnejSesji);
var poz = new PozycjaDokHandlowego(faktura);
faktura.Pozycje.AddRow(poz);
poz.Towar = towar;
poz.Ilosc = new Quantity(ilosc, towar.Jednostka.Kod);
poz.Lp = lp++;
}
transaction.Commit();
}
session.Save();
}
}
```
**WAŻNE:** W jednej sesji nie można mieszać obiektów z różnych sesji. Użyj `session.Get(obiekt)` aby doczytać obiekt w bieżącej sesji.
## Modyfikacja obiektów
### Aktualizacja pojedynczego obiektu
```csharp
public void ZmienNazweTowaru(Login login, string kod, string nowaNazwa)
{
using (var session = login.CreateSession(false, false, "EdycjaTowaru"))
{
var tm = session.GetTowary();
var towar = tm.Towary.WgKodu[kod];
if (towar != null)
{
using (var transaction = session.Logout(editMode: true))
{
towar.Nazwa = nowaNazwa;
transaction.Commit();
}
session.Save();
}
}
}
```
### Aktualizacja z transakcją biznesową
```csharp
public void AktualizujCeny(Login login, string nazwaCeny, decimal procentPodwyzki)
{
using (var session = login.CreateSession(false, false, "AktualizacjaCen"))
{
var tm = session.GetTowary();
// Jedna transakcja dla całej pętli - szybciej i atomowo
using (var transaction = session.Logout(editMode: true))
{
foreach (Towar t in tm.Towary.WgKodu)
{
var cena = t.Ceny[nazwaCeny];
if (cena != null)
{
cena.Netto = new DoubleCy(cena.Netto.Value * (1 + procentPodwyzki / 100));
}
}
transaction.Commit();
}
session.Save(); // Zapisuje wszystkie zmiany do bazy
}
}
```
## Usuwanie obiektów
### Usuwanie obiektu
```csharp
public void UsunTowar(Login login, string kod)
{
using (var session = login.CreateSession(false, false, "UsuwanieTowaru"))
{
var tm = session.GetTowary();
var towar = tm.Towary.WgKodu[kod];
if (towar != null)
{
using (var transaction = session.Logout(editMode: true))
{
towar.Delete(); // Zmiana stanu na Deleted
transaction.Commit();
}
session.Save(); // Fizyczne usunięcie z bazy
}
}
}
```
## Praca z kontekstem
Przykłady klasy parametrów dziedziczącej z `ContextBase` - patrz [contextbase.md](contextbase.md). Współdzielenie wartości przez Context - patrz [context.md](context.md). Przykłady Workera z `[Context]` i akcji w menu Czynności - patrz [worker-extender.md](worker-extender.md).
## Praca z GuidedRow
Przykłady dostępu do historii zmian (`ChangeInfos`) i pracy z załącznikami (dodawanie z transakcją, odczyt, `DefaultImage`) - patrz [datapack-guidedrow.md](datapack-guidedrow.md).
## Dane konfiguracyjne vs operacyjne
### Odczyt danych konfiguracyjnych
```csharp
// Odczyt pojedynczej wartości
var opisDlaSzt = login.ExecuteConfig(configSession =>
configSession.GetTowary().Jednostki.WgKodu["szt"]?.Opis);
// Odczyt listy wartości prostych
public string[] PobierzKodyJednostek(Login login)
{
return login.ExecuteConfig(configSession =>
{
var tm = configSession.GetTowary();
return tm.Jednostki.WgKodu.Select(j => j.Kod).ToArray();
});
}
```
**WAŻNE:** Używając `ExecuteConfig()` nie można zwracać obiektów sesyjnych z sesji konfiguracyjnej, ponieważ może być używana w innym wątku do innych celów. Zwracaj tylko wartości proste lub kopie danych.
```csharp
public void OdczytKonfiguracji(Login login)
{
// Własna sesja konfiguracyjna - gdy potrzebny dostęp do obiektów
using (var session = login.CreateSession(true, true, "Konfiguracja"))
{
var tm = session.GetTowary();
foreach (Jednostka j in tm.Jednostki.WgKodu)
{
Console.WriteLine($"{j.Kod}: {j.Opis}");
}
}
}
```
### Modyfikacja danych konfiguracyjnych
```csharp
public void DodajJednostke(Login login, string kod, string opis)
{
// Sesja edycyjna konfiguracyjna
using (var session = login.CreateSession(false, true, "DodawanieJednostki"))
{
var tm = session.GetTowary();
using (var transaction = session.Logout(editMode: true))
{
var jednostka = new Jednostka();
tm.Jednostki.AddRow(jednostka);
jednostka.Kod = kod;
jednostka.Opis = opis;
transaction.Commit();
}
session.Save();
}
}
```
## Pełny przykład - import towarów
```csharp
public class ImportTowarow
{
public void Importuj(Login login, string sciezkaPliku)
{
var dane = WczytajZPliku(sciezkaPliku);
using (var session = login.CreateSession(false, false, "ImportTowarow"))
{
var tm = session.GetTowary();
int dodano = 0;
int zaktualizowano = 0;
// Cały import w jednej transakcji
using (var transaction = session.Logout(editMode: true))
{
foreach (var wiersz in dane)
{
// Sprawdź czy towar istnieje
var towar = tm.Towary.WgKodu[wiersz.Kod];
if (towar == null)
{
// Dodaj nowy
towar = new Towar();
tm.Towary.AddRow(towar);
towar.Kod = wiersz.Kod;
dodano++;
}
else
{
zaktualizowano++;
}
// Ustaw/aktualizuj właściwości
towar.Nazwa = wiersz.Nazwa;
var cena = towar.Ceny["Hurtowa"];
cena.Netto = new DoubleCy(wiersz.Cena);
}
transaction.Commit();
}
session.Save();
Console.WriteLine($"Import zakończony:");
Console.WriteLine($" Dodano: {dodano}");
Console.WriteLine($" Zaktualizowano: {zaktualizowano}");
}
}
private List<DaneImportu> WczytajZPliku(string sciezka)
{
// Implementacja wczytywania z CSV/Excel...
return new List<DaneImportu>();
}
private class DaneImportu
{
public string Kod { get; set; }
public string Nazwa { get; set; }
public decimal Cena { get; set; }
}
}
```
## Obsługa błędów
### Wzorzec try-catch z sesją
```csharp
public void BezpiecznaOperacja(Login login)
{
using (var session = login.CreateSession(false, false, "Operacja"))
{
try
{
var tm = session.GetTowary();
using (var transaction = session.Logout(editMode: true))
{
// Operacje na danych...
var towar = new Towar();
tm.Towary.AddRow(towar);
towar.Kod = "TEST";
transaction.Commit();
}
session.Save();
}
catch (Exception ex)
{
// Logowanie błędu
Console.WriteLine($"Błąd: {ex.Message}");
// Wyjątek przed Commit() = automatyczny rollback transakcji
// Wyjątek z session.Save() = transakcja zatwierdzona w sesji, ale brak zapisu do bazy
// Sesja zostanie automatycznie zwolniona przez using
}
}
}
```
### Wzorzec z wieloma operacjami
```csharp
public void WieleOperacji(Login login, List<string> kody)
{
using (var session = login.CreateSession(false, false, "WieleOperacji"))
{
var tm = session.GetTowary();
var bledy = new List<string>();
foreach (var kod in kody)
{
try
{
using (var transaction = session.Logout(editMode: true))
{
var towar = tm.Towary.WgKodu[kod];
if (towar != null)
{
towar.Delete();
transaction.Commit();
}
}
}
catch (Exception ex)
{
bledy.Add($"{kod}: {ex.Message}");
// Kontynuuj z następnym elementem
}
}
session.Save(); // Zapisz udane operacje
if (bledy.Any())
{
Console.WriteLine("Błędy: " + string.Join(", ", bledy));
}
}
}
```