diff --git a/soneta-programming/SKILL.md b/soneta-programming/SKILL.md index e4a811c..b189120 100644 --- a/soneta-programming/SKILL.md +++ b/soneta-programming/SKILL.md @@ -1,12 +1,25 @@ --- name: soneta-programming description: > - Fundamentalne klasy ORM platformy enova365/Soneta Enterprise. Obejmuje mapowanie - obiektowo-relacyjne (Row, Table, Module), zarządzanie sesją (Session), logowanie - (Login, Database, BusApplication), paczki danych (Datapack, GuidedRow) oraz - kontekst (Context). Używaj gdy użytkownik pyta o podstawowe klasy logiki biznesowej, - strukturę obiektów ORM, sesje i transakcje, hierarchię klas Row/Table/Module, - mechanizm Datapack i synchronizację danych, lub kontekst aplikacji enova365. + Fundamentalne klasy ORM oraz wzorce kodu biznesowego platformy enova365 / Soneta + Enterprise / Triva. Obejmuje mapowanie obiektowo-relacyjne (Row, Table, Module, + GuidedRow, ExportedRow), zarządzanie sesją i transakcjami (Session, Logout, + Commit / CommitUI, Save, optimistic locking), logowanie (Login, Database, + BusApplication), paczki danych (Datapack, GuidedRow, ChangeInfos), serwerowe + filtrowanie LINQ (RowCondition, SubTable[condition]), kontekst i parametry + (Context, ContextBase), rozszerzenia modelu (Worker, Extender, [Action]), + widoki list (ViewInfo, FolderView, CreateView), cechy (Features), tłumaczenia + (Translate, ILogger), action result oraz zasady bezpiecznego kodu biznesowego + (safe-code, checklist do code review). Używaj **zawsze** gdy użytkownik: + (1) pisze, modyfikuje lub refaktoruje kod biznesowy enova365 / Soneta / + Triva — nawet jeśli nie wymienia nazw klas wprost; (2) pyta o Session, + Row, Table, Module, Login, Database, BusApplication, Context, Datapack, + GuidedRow, Worker, Extender, ViewInfo, RowCondition; (3) wspomina sesje, + transakcje biznesowe, Logout, Commit, Save, optimistic lock, blokady wierszy; + (4) prosi o code review lub bezpieczeństwo kodu biznesowego Soneta; (5) + wspomina pisanie dodatku, modułu, importu, workera, ekstendera, akcji w menu + Czynności, folderu/listy; (6) pyta o thread-safety, sesje konfiguracyjne + (ExecuteConfig), różnice dane konfiguracyjne vs operacyjne. --- # Soneta Programming Basics - Podstawowe klasy ORM @@ -320,23 +333,10 @@ Więcej wzorców (kasowanie, obsługa błędów, pełny import end-to-end) - pat ## Narzędzia pomocnicze -Skill udostępnia skrypt `scripts/scan-props.csx` (uruchamiany przez `dotnet script`) do odczytu publicznych pól klasy zagnieżdżonej `XxxModule+XxxRecord` ze skompilowanych DLL dodatku — bez ładowania IL do CLR (Roslyn `MetadataReference.CreateFromFile`). Wypisuje również właściwości klasy biznesowej (kalkulowane), Caption/Description oraz rekurencyjnie rozwija pola typu subrow z notacją kropkową. +Skill udostępnia dwa skrypty `dotnet script` (`scripts/`) do statycznej inwentaryzacji bibliotek Soneta — bez ładowania IL do CLR (Roslyn `MetadataReference.CreateFromFile`): -```bash -dotnet script ~/.claude/skills/soneta-programming/scripts/scan-props.csx \ - -- DokumentHandlowy ./bin/Debug/net8.0 -``` - -Szczegóły, kody wyjścia i ograniczenia: [references/scan-props.md](references/scan-props.md). - -Drugi skrypt — `scripts/scan-modules.csx` — listuje wszystkie moduły (`*Module` dziedziczące z `Soneta.Business.Module`) oraz znajdujące się w nich tabele (`RowType`/`TableType` z Caption/Description). Pomocne przy wstępnej inwentaryzacji bibliotek, zanim sięgniesz po `scan-props.csx` dla konkretnej tabeli. - -```bash -dotnet script ~/.claude/skills/soneta-programming/scripts/scan-modules.csx \ - -- ./bin/Debug/net8.0 -``` - -Szczegóły: [references/scan-modules.md](references/scan-modules.md). +- `scan-modules.csx` — listuje moduły (`*Module`) i ich tabele (`*Row`/`*Table`) z Caption/Description. Dobre na start. Szczegóły, parametry i przykłady uruchomienia: [references/scan-modules.md](references/scan-modules.md). +- `scan-props.csx` — wypisuje pola i właściwości kalkulowane konkretnej klasy biznesowej, rekurencyjnie po polach typu subrow. Sięgnij po niego, gdy znasz już tabelę i potrzebujesz jej kontraktu. Szczegóły: [references/scan-props.md](references/scan-props.md). ## Konwencje nazewnicze diff --git a/soneta-programming/references/examples.md b/soneta-programming/references/examples.md index 4cbd19d..8e4f058 100644 --- a/soneta-programming/references/examples.md +++ b/soneta-programming/references/examples.md @@ -17,15 +17,11 @@ Praktyczne przykłady użycia podstawowych klas logiki biznesowej enova365/Sonet ## Ważne zasady -### Thread-safety +Ten plik zakłada znajomość fundamentów — przed sięgnięciem po przykłady upewnij się, że są jasne: -**Obiekty single-threaded** - nie współdziel między wątkami: -- `Session`, `Module`, `Table`, `Row`, `Context` - -**Obiekty multi-threaded** - można współdzielić: -- `BusApplication`, `Database`, `Login` - -Każdy wątek powinien tworzyć własną sesję (Login można współdzielić). +- **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 @@ -39,22 +35,6 @@ var kadry = session.GetKadry(); var bm = session.GetBusiness(); ``` -### Transakcje biznesowe - -**Każda zmiana obiektu MUSI być w transakcji** `Session.Logout(editMode: true)`: - -```csharp -using (var transaction = session.Logout(editMode: true)) -{ - // Zmiany: dodawanie, modyfikacja, kasowanie - obiekt.Wlasciwosc = nowaWartosc; - transaction.Commit(); // Zatwierdza zmiany -} -// Brak Commit() = automatyczny rollback - -session.Save(); // Zapis do bazy danych -``` - ## Dostęp do danych ### Odczyt listy towarów diff --git a/soneta-programming/references/rowcondition.md b/soneta-programming/references/rowcondition.md index 664c7df..4866e73 100644 --- a/soneta-programming/references/rowcondition.md +++ b/soneta-programming/references/rowcondition.md @@ -4,6 +4,29 @@ Najwygodniejsze API to budowa warunku z wyrażeń LINQ (`Expression>`) przez `RowCondition.FromExpression(...)` oraz aplikowanie wyrażeń bezpośrednio do `SubTable` i `View` przez indeksator i `AddExpression(...)`. +## Spis treści + +- [Najważniejsze zasady](#najważniejsze-zasady) +- [Wzorce użycia w kodzie](#wzorce-użycia-w-kodzie) + - [1. Indeksator `SubTable[expression]` - logika biznesowa](#1-indeksator-subtableexpression---logika-biznesowa) + - [2. `View.AddExpression(...)` - listy w UI](#2-viewaddexpression---listy-w-ui) + - [3. `Query.Table.AddExpression(...)` - zapytania niskopoziomowe](#3-querytableaddexpression---zapytania-niskopoziomowe) + - [4. `RowCondition.FromExpression(...)` - jawne budowanie warunku](#4-rowconditionfromexpression---jawne-budowanie-warunku) +- [Zakres możliwych wyrażeń](#zakres-możliwych-wyrażeń) + - [Odwołania do pól](#odwołania-do-pól) + - [Wartości po stronie klienta](#wartości-po-stronie-klienta) + - [Typy proste, enum, int](#typy-proste-enum-int) + - [Bool](#bool) + - [String](#string) + - [Null / not null](#null--not-null) + - [Referencje](#referencje) + - [Operator IN - przynależność do zbioru](#operator-in---przynależność-do-zbioru) + - [Operatory logiczne i wyrażenia złożone](#operatory-logiczne-i-wyrażenia-złożone) + - [Pola złożone (Quantity, Currency, FromTo)](#pola-złożone-quantity-currency-fromto) + - [Kolekcje powiązane (podlisty)](#kolekcje-powiązane-podlisty) +- [Ograniczenia - co się nie skompiluje do SQL](#ograniczenia---co-się-nie-skompiluje-do-sql) +- [Kiedy używać czego](#kiedy-używać-czego) + ## Najważniejsze zasady * W wyrażeniu LINQ można odwoływać się **wyłącznie do pól bazodanowych** (kolumn tabeli, pól złożonych, kolekcji powiązanych, cech). Próba użycia pola niebazodanowego rzuca `LinqConditionException`. diff --git a/soneta-programming/references/safe-code.md b/soneta-programming/references/safe-code.md index a56cc94..a08b8c7 100644 --- a/soneta-programming/references/safe-code.md +++ b/soneta-programming/references/safe-code.md @@ -114,7 +114,8 @@ Wyjątek po `Commit()` ale przed `Save()` nie wycofuje zmian z bieżącej sesji ### 5.2 Komunikaty walidacyjne przez `Translate` ```csharp -throw new RowException(this, "Pole {0} jest wymagane".Translate(), nameof(Nazwa)); +throw new RowException(this, "Pole jest wymagane".Translate()); +throw new RowException(this, "Pole {0} jest wymagane".TranslateFormat(nameof(Nazwa))); ``` --- diff --git a/soneta-programming/references/session-login.md b/soneta-programming/references/session-login.md index 8156c9e..731ff5c 100644 --- a/soneta-programming/references/session-login.md +++ b/soneta-programming/references/session-login.md @@ -2,6 +2,16 @@ Dokumentacja klas zarządzających połączeniem z bazą danych i sesjami w platformie enova365/Soneta. +## Spis treści + +- [Hierarchia obiektów](#hierarchia-obiektów) +- [Klasa BusApplication](#klasa-busapplication) — singleton, dostęp do instancji, właściwości +- [Klasa Database](#klasa-database) — konfiguracja, logowanie do bazy +- [Klasa Login](#klasa-login) — tworzenie, dostęp do operatora, tworzenie sesji, dane konfiguracyjne, sygnatury `CreateSession` +- [Klasa Session](#klasa-session) — tworzenie, typy sesji, właściwości, zarządzanie danymi, sesje konfiguracyjne, wiele sesji, transakcje (`Logout`, `Commit`/`CommitUI`) +- [Kompletny przykład](#kompletny-przykład) +- [Thread-safety](#thread-safety) — które obiekty można współdzielić, które nie + ## Hierarchia obiektów ``` @@ -229,7 +239,7 @@ using (var session2 = login.CreateSession(readOnly: true, config: false, name: " ### Transakcje biznesowe - Session.Logout() -**WAŻNE:** Każda zmiana obiektu biznesowego MUSI być w transakcji! +**Każda modyfikacja obiektu MUSI być w transakcji biznesowej** otwieranej przez `Session.Logout(editMode: true)` — dotyczy dodawania, modyfikacji właściwości oraz kasowania. ```csharp using (var session = login.CreateSession(readOnly: false, config: false, name: "Edycja")) diff --git a/soneta-programming/references/viewinfo.md b/soneta-programming/references/viewinfo.md index 5eeac4d..532dbb3 100644 --- a/soneta-programming/references/viewinfo.md +++ b/soneta-programming/references/viewinfo.md @@ -7,6 +7,19 @@ ViewInfo to **kod UI** (patrz "Kod biznesowy vs UI" w głównym `SKILL.md`). Skill `soneta-form-xml` opisuje pełną składnię plików `viewform.xml`/`pageform.xml` (elementy `DataForm`, `Flow`, `Grid`, `Field`, `Appearance`, `GroupBy`, atrybuty `EditValue`, `Visibility`, `IsReadOnly`, `Condition` itd.). Sięgaj do niego za każdym razem, gdy edytujesz lub generujesz XML formularza — bez tej wiedzy łatwo wygenerować nieprawidłowe znaczniki. +## Spis treści + +- [Rejestracja folderu — atrybut `FolderView`](#rejestracja-folderu--atrybut-folderview) +- [Anatomia klasy ViewInfo](#anatomia-klasy-viewinfo) +- [Eventy — gdzie zaszywać logikę](#eventy--gdzie-zaszywać-logikę) + - [Kanoniczna para `InitContext` + `CreateView`](#kanoniczna-para-initcontext--createview) +- [Klasa parametrów (`Params` / `WParams` / lub inna nazwa)](#klasa-parametrów-params--wparams--lub-inna-nazwa) +- [Filtrowanie View — paleta narzędzi](#filtrowanie-view--paleta-narzędzi) + - [Filtrowanie po cechach (Features)](#filtrowanie-po-cechach-features) +- [Powiązanie z `viewform.xml`](#powiązanie-z-viewformxml) +- [Pełny przykład minimalny](#pełny-przykład-minimalny) +- [Pułapki i dobre praktyki](#pułapki-i-dobre-praktyki) + --- ## Rejestracja folderu — atrybut `FolderView` diff --git a/soneta-programming/references/worker-extender.md b/soneta-programming/references/worker-extender.md index 1fb0695..9a55d9e 100644 --- a/soneta-programming/references/worker-extender.md +++ b/soneta-programming/references/worker-extender.md @@ -6,14 +6,13 @@ Oba korzystają z [Context](context.md) do pobierania parametrów. ## Obiekty Worker -Dodają dodatkowe properties wyliczane do obiektów, które mogą być stosowane w bindowaniu lub pozwalają na -definiowanie pozycji w menu Czynności. +Worker dorzuca do obiektu danych dodatkowe properties wyliczane (do użycia w bindowaniu) oraz pozycje w menu Czynności. -* Worker jest zawsze przypisany do obiektu danych. -* W nazwie klasy powinno się stosować sufiks `Worker` -* Nazwa klasy worker powinna określać jego działanie. -* Może być inicjowany z context za pomocą `[Context]` -* Rejestracja za pomocą atrybutu assembly z dwoma parametrami `[Worker]` - zalecana wersja generic +* Przypisuj worker do konkretnego obiektu danych — worker zawsze działa w kontekście jednego typu. +* Dodawaj do nazwy klasy sufiks `Worker` (np. `WyliczenieStanMagazynuWorker`). +* Wybieraj nazwę klasy opisującą działanie, nie technikę. +* Inicjuj parametry z kontekstu przez `[Context]`. +* Rejestruj przez generyczny atrybut `[assembly: Worker]` — to wersja zalecana. ### Rejestracja worker @@ -95,7 +94,7 @@ public class SendEmailsForKontrahentWorker int counter = 0; foreach (var k in Kontrahenci) { - if (!string.IsNullOrEmpty(k.Email)) + if (!k.Email.IsNullOrEmpty()) { WyslijEmail(k.Email); ++counter;