From 3d58eadd16453c554b20949cef3e801b7eef4fd4 Mon Sep 17 00:00:00 2001 From: Marcin Wojas Date: Mon, 18 May 2026 22:25:47 +0200 Subject: [PATCH] features.md --- soneta-programming/SKILL.md | 1 + soneta-programming/references/features.md | 104 ++++++++++++++++++++++ soneta-programming/references/viewinfo.md | 19 +++- 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 soneta-programming/references/features.md diff --git a/soneta-programming/SKILL.md b/soneta-programming/SKILL.md index 3ad26ba..6735c3b 100644 --- a/soneta-programming/SKILL.md +++ b/soneta-programming/SKILL.md @@ -30,6 +30,7 @@ SKILL.md zawiera "duży obraz" - hierarchię klas, thread-safety, kanoniczne wzo | Action result zwracany przez worker / extender / Command - raporty, dialogi, nawigacja | [references/action-result.md](references/action-result.md) | | RowCondition - serwerowe warunki LINQ, filtrowanie SubTable / View / Query | [references/rowcondition.md](references/rowcondition.md) | | ViewInfo - definicja widoków list (folderów), CreateView, klasa Params, powiązanie z viewform.xml | [references/viewinfo.md](references/viewinfo.md) | +| Cechy (Features) - tabela Features, typy cech, dostęp typowany/nietypowany, bindowanie w form.xml | [references/features.md](references/features.md) | | Gotowe wzorce kodu end-to-end (import, CRUD, obsługa błędów) | [references/examples.md](references/examples.md) | ## Architektura warstw diff --git a/soneta-programming/references/features.md b/soneta-programming/references/features.md new file mode 100644 index 0000000..cd2ccb9 --- /dev/null +++ b/soneta-programming/references/features.md @@ -0,0 +1,104 @@ +# Cechy (Features) - dodatkowe informacje na obiektach biznesowych + +Cechy to dodatkowe, dynamicznie definiowane informacje przypisane do obiektów biznesowych (Row). Każda tabela biznesowa ma własny zestaw cech, identyfikowanych po nazwie. Definicje przechowywane są w tabeli `FeatureDefs` (`FeatureDefinition`). Ich tworzenie i modyfikacja **nie wymaga konwersji bazy danych** — cechy mogą być definiowane podczas wdrożenia. + +Cechy występują w dwóch wariantach: + +- **Bazodanowe** — wartość przechowywana w tabeli `Features` powiązanej z daną tabelą biznesową. +- **Algorytmiczne** — wartość obliczana w locie przez algorytm; ustawienie cechy także wykonuje algorytm. + +## Struktura tabeli Features + +``` +[Parent] [int] NOT NULL -- ID Row obiektu biznesowego +[ParentType] [nvarchar(16)] NOT NULL -- tabela, do której zarejestrowano cechę +[Name] [nvarchar(30)] NOT NULL -- nazwa cechy +[Lp] [int] NOT NULL -- 0 dla zwykłych cech; >0 dla historycznych / wielowartościowych +[DataKey] [nvarchar(30)] NULL -- główne, indeksowane pole z wartością +[Data] [nvarchar(3000)] NULL -- duplikat DataKey (≤30 znaków) lub właściwa wartość (>30 znaków) +``` + +`Parent` + `ParentType` jednoznacznie identyfikują biznesowy Row, do którego należy cecha. `Lp` rozdziela kolejne wpisy cech historycznych lub wielowartościowych. + +`DataKey` jest indeksowany — używaj go do wyszukiwań. Gdy zapis mieści się w 30 znakach, `Data` zawiera tę samą wartość; dla dłuższych — pełną wartość trzyma `Data`. + +## Typy cech i ich reprezentacja fizyczna + +Poniższa tabela obejmuje typy liczbowe, daty/czasu, walutowe i jednostkowe (`FeatureTypeNumber`). + +| Caption | FeatureTypeNumber | Value | Soneta.Type | Przykład zapisu w DataKey/Data | Uwagi | +|---|---|---|---|---|---| +| Liczba całkowita | `Int` | 0 | `int` | ` 44` | string 10-znakowy, wyrównany do prawej spacjami | +| Warunek | `Bool` | 1 | `bool` | `1` lub `0` | zapis jak `int` | +| Kwota | `Decimal` | 3 | `Decimal` | ` 1.01000000` | 2 miejsca po przecinku w UI, fizycznie decimal 8 m.p., string 20 znaków, wyrównany do prawej | +| Liczba rzeczywista | `Double` | 4 | `Double` | ` 1.01234568` | 8 miejsc po przecinku, string 20 znaków, wyrównany do prawej | +| Data | `Date` | 5 | `Date` | `2025-01-22` | format `rrrr-MM-dd` | +| Czas | `Time` | 6 | `Time` | `0000030:20` | format `hhhhhhh:mm` — 7 znaków totalHours + `:` + minuty | +| Okres dat | `FromTo` | 7 | `FromTo` | `2025-04-01...2025-04-30` | dwie daty `rrrr-MM-dd` rozdzielone `...` | +| Ułamek | `Fraction` | 8 | `Fraction` | `12345/6789` | dwa inty rozdzielone `/` | +| Kwota z walutą | `Currency` | 9 | `Currency` | `PLN 1.12000000` | 2 m.p. po zaokrągleniu, sztywny string 24-znakowy | +| Procent | `Percent` | 10 | `Percent` | ` 0.20110000` | 20,11% zapisane jako `0.2011` | +| Liczba z walutą | `DoubleCy` | 11 | `DoubleCy` | `PLN 1.12345679` | 8 m.p., string 24-znakowy | +| Miesiąc w roku | `YearMonth` | 12 | `YearMonth` | `2025/02` | rok i miesiąc rozdzielone `/` | +| Czas z dokładnością do sekundy | `TimeSec` | 17 | `TimeSec` | `30:20:10` | format `hh:mm:ss` | +| Ilość | `Amount` | 18 | `Amount` | `szt 100.40000000` | jak `Currency`, ale jednostka opcjonalna | + +## Dostęp do cechy w kodzie + +### Dostęp nietypowany przez indeksator Row + +```csharp +Row row = ...; +object v = row["NazwaCechy"]; +if (v == null) { + // cecha nie istnieje +} +``` + +### Dostęp typowany przez Row.Features + +```csharp +Row fv = Session.GetHandel().DokHandlowe[123]; + +bool b = fv.Features.GetBool("CechaBool"); +Currency c = fv.Features.GetCurrency("CechaCurrency"); +Date dt = fv.Features.GetDate("CechaDate"); +string s = fv.Features.GetString("CechaString"); +int i = fv.Features.GetInt("CechaInt"); +decimal d = fv.Features.GetDecimal("CechaDecimal"); +``` + +### Ustawienie wartości + +Tak jak każda modyfikacja Row, ustawienie cechy wymaga transakcji edycyjnej: + +```csharp +using (var t = Session.Logout(editMode: true)) { + fv["CechaString"] = "Nowa wartość cechy"; + fv["CechaInt"] = 12345; + t.Commit(); +} +``` + +Dla cech algorytmicznych przypisanie wartości wywołuje algorytm zdefiniowany w `FeatureDefinition`. + +## Bindowanie do cech w form.xml + +W formularzach UI cechy adresuje się przez ścieżkę `Features.NazwaCechy` — bezpośrednio na bieżącym Row lub przez relację do innego obiektu: + +```xml + + + + +``` + +## Filtrowanie View po cechach + +`Features.X` nie jest typowaną property klasy Row. Dla filtrów po cechach używaj `FieldCondition` ze string-path `"Features.NazwaCechy"`: + +```csharp +view.Condition &= new FieldCondition.Equal("Features.GrupaTowaru", "Telewizor"); +view.Condition &= new FieldCondition.GreaterEqual("Features.Przekatna", 50); +view.Condition &= new FieldCondition.Equal("Features.SmartTV", true); +``` diff --git a/soneta-programming/references/viewinfo.md b/soneta-programming/references/viewinfo.md index 3d07ff4..73a9d0f 100644 --- a/soneta-programming/references/viewinfo.md +++ b/soneta-programming/references/viewinfo.md @@ -222,9 +222,26 @@ if (pars.TylkoPodgląd) { Reguły wyboru: - **`AddExpression`** — gdy filtr da się wyrazić jako LINQ na właściwościach kolumn. Preferowany. -- **`Condition &=`** — gdy potrzebujesz dołożyć `RowCondition` bezpośrednio (`Exists`, `Or`, gotowy obiekt). +- **`Condition &=`** — gdy potrzebujesz dołożyć `RowCondition` bezpośrednio (`Exists`, `Or`, gotowy obiekt) **oraz gdy filtrujesz po cechach (`Features.X`) — LINQ tego nie obsługuje**. - **`FilterCondition`** — tylko jako ostatnia deska ratunku. Działa po stronie klienta, nie da się przez nią paginować/sortować po SQL-u. +### Filtrowanie po cechach (Features) + +Cechy są dynamicznymi polami trzymanymi w osobnej tabeli — **nie są typowanymi properties klasy Row**. Dla cech używaj `FieldCondition` ze string-path `"Features.NazwaCechy"`: + +```csharp +// Zwykłe pola Towaru — LINQ (preferowane, walidowane przy kompilacji) +view.AddExpression(t => !t.Blokada && t.Typ == TypTowaru.Towar); + +// Cechy — FieldCondition ze string-path (jedyna droga) +view.Condition &= new FieldCondition.Equal("Features.GrupaTowaru", "Telewizor"); +view.Condition &= new FieldCondition.Equal("Features.Marka", "Samsung"); +view.Condition &= new FieldCondition.GreaterEqual("Features.Przekatna", 50); +view.Condition &= new FieldCondition.LessEqual("Features.Przekatna", 75); +``` + +Path `"Features.NazwaCechy"` działa też w `LikeConditionProvider`, `OrderBy` widoku i bindingach `viewform.xml` (`EditValue="{Features.Marka}"`). Pełen opis cech (typy, składowanie, dostęp programowy) — patrz [features.md](features.md). + Pełen opis `RowCondition` (rodzaje, `Exists`, `Or`/`And`, użycie w `SubTable`) — patrz [rowcondition.md](rowcondition.md). ---