Porządki i usprawnienia

This commit is contained in:
Marcin Wojas
2026-05-19 11:27:12 +02:00
parent 98e3ead84d
commit 37d92acfe0
7 changed files with 82 additions and 56 deletions
+22 -22
View File
@@ -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
+4 -24
View File
@@ -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
@@ -4,6 +4,29 @@
Najwygodniejsze API to budowa warunku z wyrażeń LINQ (`Expression<Predicate<TRow>>`) 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`.
+2 -1
View File
@@ -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)));
```
---
+11 -1
View File
@@ -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"))
+13
View File
@@ -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`
@@ -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<WorkerType, DataType>]` - 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<WorkerType, DataType>]` — 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;