Porządki i usprawnienia
This commit is contained in:
+22
-22
@@ -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
|
||||
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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)));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user