16 KiB
name, description
| name | description |
|---|---|
| soneta-programming | Klasy ORM i wzorce kodu biznesowego enova365 / Soneta Enterprise / Triva: Row/Table/Module, sesja i transakcje (Session, Commit/CommitUI, Save, optimistic lock), Login/Database/BusApplication, Datapack/GuidedRow/ExportedRow, serwerowy LINQ (RowCondition, SubTable[condition]), Context, Worker/Extender/[Action], ViewInfo/FolderView, Features, Translate/ILogger oraz zasady bezpiecznego kodu (safe-code, code review). Używaj gdy użytkownik: (1) pisze, modyfikuje lub refaktoruje kod biznesowy enova365/Soneta/Triva; (2) pyta o Session, Row, Table, Module, Login, Database, Context, Datapack, Worker, Extender, ViewInfo, RowCondition; (3) wspomina sesje, transakcje, Commit, Save, optimistic lock, blokady wierszy; (4) prosi o code review kodu biznesowego Soneta; (5) pisze dodatek, worker, extender, akcję w menu Czynności, folder/listę; (6) pyta o thread-safety, ExecuteConfig, dane konfiguracyjne vs operacyjne. |
Soneta Programming Basics - Podstawowe klasy ORM
Skill zawiera dokumentację fundamentalnych klas logiki biznesowej platformy enova365/Soneta Enterprise. Klasy te stanowią podstawę mapowania obiektowo-relacyjnego (ORM) i są niezbędne do tworzenia kodu i dodatków.
Code review / refaktoring: po napisaniu nowego kodu biznesowego oraz po każdym refaktoringu, zawsze zweryfikuj go względem references/safe-code.md. Ten sam dokument służy jako lista kontrolna do review PR-ów.
Mapa skilla
SKILL.md zawiera "duży obraz" - hierarchię klas, thread-safety, kanoniczne wzorce. Po szczegóły konkretnego tematu sięgaj do referencji:
| Temat | Gdzie szukać |
|---|---|
| Hierarchia ORM, Row / Table / Module, klucze, ISessionable | sekcje poniżej |
| Sesje, transakcje, Login, Database, BusApplication, optimistic locking | references/session-login.md |
| Paczki danych, Datapack, GuidedRow, ExportedRow, synchronizacja, blokady | references/datapack-guidedrow.md |
| Klasa Context - dane z UI, zaznaczenia, parametry workera | references/context.md |
| Klasy parametrów (ContextBase) - filtry, trwałość, InvokeChanged | references/contextbase.md |
| Obiekty Worker i Extender - rozszerzenia modelu, akcje w menu Czynności | references/worker-extender.md |
| Serwisy biznesowe (App / Database / Login / Session scope) | references/services.md |
| Tłumaczenia (Translate, TranslateIgnore), ILogger, ActSource | references/translations-logging.md |
| Action result zwracany przez worker / extender / Command - raporty, dialogi, nawigacja | references/action-result.md |
| RowCondition - serwerowe warunki LINQ, filtrowanie SubTable / View / Query | references/rowcondition.md |
| ViewInfo - definicja widoków list (folderów), CreateView, klasa Params, powiązanie z viewform.xml | references/viewinfo.md |
| Cechy (Features) - tabela Features, typy cech, dostęp typowany/nietypowany, bindowanie w form.xml | references/features.md |
| Gotowe wzorce kodu end-to-end (import, CRUD, obsługa błędów) | references/examples.md |
Receptury kodu per obiekt biznesowy (domeny) — Kontrahent (pola, kolekcje, workery, finanse, RODO, KSeF) |
references/domeny/kontrahent.md |
Receptury kodu per obiekt biznesowy (domeny) — DokumentHandlowy (faktury/magazynowe/zamówienia/korekty, relacje IRelacjeService, cykl życia, magazyn/partie/obroty, VAT/waluty, płatności, KSeF/fiskal/Intrastat, wydruki) |
references/domeny/dokument-handlowy.md |
Receptury kodu per obiekt biznesowy (domeny) — Pracownik/Kadry-Płace (zatrudnienie i dane kadrowe, historia PracHistoria+Etat, dodatki, nieobecności/limity, plan pracy/RCP, umowy cywilnoprawne, naliczanie wypłat, listy płac, wydruki PDF) |
references/domeny/pracownik.md |
| Zasady bezpiecznego kodu biznesowego — checklist do review i refaktoringu | references/safe-code.md |
| Skanowanie pól obiektu biznesowego z DLL (Roslyn MetadataReference) | references/scan-props.md |
Inwentaryzacja modułów i tabel (*Module / *Row / *Table) z DLL |
references/scan-modules.md |
Inwentaryzacja workerów i extenderów ([Worker<…>]) z DLL |
references/scan-workers.md |
Architektura warstw
BusApplication.Instance (singleton) - multithreaded
└── Database
└── Login
└── Session - single-threaded
└── Module
└── Table
└── Row
3 poziomy logiki biznesowej
| Poziom | Opis | Przykłady klas |
|---|---|---|
| 1. Bazowe | Klasy wspólne dla wszystkich modułów (Soneta.Business.dll) | Row, Table, Module, Session, Context |
| 2. Generowane | Klasy generowane przez BusinessGenerator z *.business.xml (sufiksy: Row, Table, Module) |
TowarRow, TowarTable, TowaryModule |
| 3. Implementowane | Klasy konkretne tworzone przez programistę | Towar, Towary (bez sufiksów) |
BusinessGenerator jest automatycznie uruchamiany podczas kompilacji dla plików *.business.xml. Szczegółowy opis definiowania business.xml znajduje się w skill soneta-business-xml.
Hierarchia głównych klas
Row (abstrakcyjna)
└── GuidedRow (+ Guid, Attachments, ChangeInfos)
└── ExportedRow (+ Exported flag - rozróżnia dane konfiguracyjne od operacyjnych)
Table (abstrakcyjna)
└── GuidedTable (indeksator po Guid)
└── ExportedTable
Module (abstrakcyjna)
└── [NazwaModulu]Module (np. TowaryModule)
Szczegóły GuidedRow / ExportedRow (flaga Exported, atrybuty guided / relguided w business.xml, ChangeInfos, blokady) - patrz references/datapack-guidedrow.md.
Thread-safety
Obiekty single-threaded (NIE współdzielić między wątkami)
SessionModuleTableRowContext- oraz wszystkie klasy pochodne
Obiekty multi-threaded (można współdzielić)
BusApplicationDatabaseLogin
Klasa Session - fundamenty
Session to kluczowa klasa do zarządzania danymi. Każda operacja na danych wymaga sesji. Sesja jest single-threaded i implementuje IDisposable - zawsze opakowuj w using.
Session session = login.CreateSession(readOnly: false, config: false, name: "MojaSesja");
Każda modyfikacja obiektu MUSI być w transakcji biznesowej otwieranej przez Session.Logout(editMode: true) - dotyczy dodawania, modyfikacji właściwości oraz kasowania:
using (var transaction = session.Logout(editMode: true))
{
towar.Nazwa = "Zmieniona nazwa";
transaction.Commit(); // Commit() w kodzie biznesowym
// transaction.CommitUI(); // CommitUI() w kodzie UI (worker, extender, Command)
}
session.Save(); // zapis do bazy - optimistic-lock; konflikty wykrywane tu
Brak Commit() = automatyczny rollback przy Dispose() - dotyczy też transakcji tylko do odczytu.
Pełna dokumentacja (typy sesji edycyjna / readonly / konfiguracyjna, transakcje zagnieżdżone, Commit vs CommitUI, optimistic locking, mieszanie obiektów z różnych sesji przez session.Get(obiekt)) - patrz references/session-login.md.
Klasa Module
Moduł grupuje logicznie powiązane tabele. Nie ma odwzorowania w bazie danych.
// Dostęp do modułu - extension method (zalecane)
var tm = session.GetTowary();
var hm = session.GetHandel();
var crm = session.GetCRM();
var bm = session.GetBusiness();
// Dostęp do tabel
Towary towary = tm.Towary;
Jednostki jednostki = tm.Jednostki;
// Moduł implementuje ISessionable
Session s = tm.Session;
Klasa Table
Reprezentuje tabelę w bazie danych. Udostępnia dostęp do kolekcji wierszy.
var towary = tm.Towary;
// Iteracja po kluczu podstawowym
foreach (Towar t in towary.WgKodu) { ... }
// Iteracja po innym kluczu
foreach (Towar t in towary.WgNazwy) { ... }
// Właściwości
Table.AccessRight // Prawa dostępu
Table.Session // Sesja (ISessionable)
Table.Module // Moduł nadrzędny
Table.PrimaryKey // Klucz podstawowy
Klasa Row
Reprezentuje pojedynczy wiersz (rekord) z tabeli.
Właściwości bazowe
Row.ID // int - PODSTAWOWY identyfikator obiektu w tabeli (autoincrement, Primary Key)
Row.State // RowState - stan obiektu w sesji
Row.Table // Table - tabela nadrzędna
Row.Module // Module - moduł
Row.Session // Session - sesja
ID jest automatycznie generowany przez bazę danych i stanowi klucz główny (Primary Key) tabeli.
Stany obiektu (RowState)
| Stan | Opis |
|---|---|
Detached |
Nowy obiekt, nie przypisany do tabeli |
Unchanged |
Wczytany z bazy, bez zmian |
Modified |
Zmodyfikowany w sesji |
Added |
Nowy, dodany do tabeli, nie zapisany w bazie |
Deleted |
Skasowany, do usunięcia z bazy |
Klucze i indeksy
Definiowane w *.business.xml, mapowane na indeksy w bazie danych.
<key name="WgKodu" keyunique="true" keyprimary="true">
<keycol name="Kod"/>
</key>
| Atrybut | Znaczenie |
|---|---|
keyprimary="true" |
Klucz podstawowy (domyślne sortowanie) |
keyunique="true" |
Wartości unikalne w tabeli |
Uwaga: keyprimary w business.xml to nie to samo co Primary Key w bazie (który jest zawsze na kolumnie ID).
Interfejs ISessionable
public interface ISessionable {
Session Session { get; }
}
Implementują go: Session, Module, Table, Row, Context, Key.
Używany jako argument funkcji wymagających kontekstu sesji:
// Metoda statyczna GetInstance - akceptuje ISessionable
public static TowaryModule GetInstance(ISessionable session)
// Extension method - wygodniejsza składnia (tylko dla Session)
public static TowaryModule GetTowary(this Session session)
Zalecane użycie:
// Extension method (prostsze)
var tm = session.GetTowary();
var tm = context.Session.GetTowary();
var tm = towar.Session.GetTowary();
// GetInstance (gdy mamy ISessionable, ale property Session jest niedostępne)
var tm = TowaryModule.GetInstance(sessionable);
Kod biznesowy vs UI
Kod biznesowy realizuje operacje logiki biznesowej (jak backend). Kod UI (frontend) jest odpowiedzialny za prezentację danych i interakcję z użytkownikiem. Kod biznesowy może być umieszczony w tej samej klasie z kodem UI.
Kod UI to np.:
- obiekty
View,ViewInfo, extender - metody sterujące
IsReadOnlyXxx,IsVisibleXxxx,GetListXxx,IsEnabledXxx,GetNameXxx,GetAppearanceXxx
Ważne zasady do stosowania w kodzie biznesowym
- Nie używaj żadnych obiektów kodu UI, w szczególności
View- zamiast tego możesz użyćSubTable[condition]. - Nie należy stosować warunków na prawa dostępu (np.
if (Table.AccessRight == AccessRights.Denied) {...}).
Szczegóły konstruowania ViewInfo (atrybut FolderView, eventy CreateView/InitContext, klasa Params, powiązanie z viewform.xml) opisuje references/viewinfo.md.
Metadane modułów, tabel, kluczy, pól
Dostęp do metadanych obiektów biznesowych jest dostępny przez metody static klasy ApplicationInfo.
- Odczyt informacji o tabeli:
TableInfo info = ApplicationInfo.GetTableInfo(nazwaTabeli). Istnieje tylko jedna referencja obiektuTableInfodla tabeli - można używaćReferenceEquals,Dictionary, itp. - Wszystkie tabele:
ApplicationInfo.GetTablesInfo(). - Tabele dla modułu:
ApplicationInfo.GetModuleInfo(moduleName).TableInfos.
Wykorzystuj TableInfo do weryfikacji tabeli
Row row1 = ...;
Row row2 = ...;
if (row1.Table.TableInfo == row2.Table.TableInfo) {
// Ta sama tabela, nawet gdy różne sesje
}
Szybki start - wzorce kodu
Odczyt danych
using (var session = login.CreateSession(readOnly: true, config: false, name: "Odczyt"))
{
var tm = session.GetTowary();
foreach (Towar t in tm.Towary.WgKodu)
{
Console.WriteLine($"{t.Kod}: {t.Nazwa}");
}
}
Tworzenie nowego obiektu
using (var session = login.CreateSession(readOnly: false, config: false, name: "Dodawanie"))
{
var tm = session.GetTowary();
using (var transaction = session.Logout(editMode: true))
{
var towar = new Towar();
tm.Towary.AddRow(towar);
towar.Kod = "NOWY001";
towar.Nazwa = "Nowy towar";
transaction.Commit();
}
session.Save();
}
Modyfikacja istniejącego obiektu
using (var session = login.CreateSession(readOnly: false, config: false, name: "Edycja"))
{
var tm = session.GetTowary();
var towar = tm.Towary.WgKodu["STARY001"];
if (towar != null)
{
using (var transaction = session.Logout(editMode: true))
{
towar.Nazwa = "Zmieniona nazwa";
transaction.Commit();
}
}
session.Save();
}
Więcej wzorców (kasowanie, obsługa błędów, pełny import end-to-end) - patrz references/examples.md.
Narzędzia pomocnicze
Skill udostępnia trzy skrypty dotnet script (scripts/) do statycznej inwentaryzacji bibliotek Soneta — bez ładowania IL do CLR (Roslyn MetadataReference.CreateFromFile):
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.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.scan-workers.csx— wypisuje na stdout JSON z workerami i extenderami zarejestrowanymi atrybutem assembly[Worker<…>], pogrupowanymi wgDataType. Dla każdej klasy: parametry inicjowane zContext(ctor +[Context], z rozwinięciem pod-property dla typów dziedziczących zContextBase), property do bindowania, akcje menu Czynności. Opcjonalny drugi argument filtruje wynik do konkretnego typu danych (np.DokumentHandlowy) — w praktyce konieczny, bo pełne skanowanie zwraca tysiące rejestracji. Wynik łatwo przetwarzaćjq. Szczegóły: references/scan-workers.md.
Konwencje nazewnicze
| Element | Konwencja | Przykład |
|---|---|---|
| Klasa wiersza (Row) | PascalCase, l.poj. | Towar, Kontrahent |
| Klasa tabeli | PascalCase, l.mn. | Towary, Kontrahenci |
| Klasa modułu | Nazwa + Module | TowaryModule |
| Klucz | Wg + nazwa kolumny | WgKodu, WgNazwy |
| Namespace | Soneta.NazwaModułu | Soneta.Towary |
Język identyfikatorów
| Typ | Język | Przykłady |
|---|---|---|
| Logika biznesowa | polski | Towar, Kontrahent, DokumentHandlowy, Faktura |
| Identyfikatory systemowe | angielski | Session, Context, Row, Table, Module |
Można łączyć polski i angielski w nazwach metod i klas:
RetrieveTowary()
UpdateKontrahent()
GetDokumentyHandlowe()
CreateFaktura()