10 KiB
Session, Login, Database, BusApplication
Dokumentacja klas zarządzających połączeniem z bazą danych i sesjami w platformie enova365/Soneta.
Hierarchia obiektów
BusApplication (Singleton)
└── Database[] (kolekcja baz danych)
└── Login (uwierzytelniony użytkownik)
└── Session[] (sesje robocze)
└── Module → Table → Row
BusApplication
Singleton reprezentujący instancję aplikacji ERP. Tworzony podczas inicjalizacji systemu.
Dostęp do instancji
// Singleton
BusApplication app = BusApplication.Instance;
// Dostęp do bazy danych po nazwie
Database db = BusApplication.Instance["BazaDemo"];
// Iteracja po wszystkich bazach
foreach (Database db in BusApplication.Instance)
{
Console.WriteLine(db.Name);
}
Właściwości
| Właściwość | Typ | Opis |
|---|---|---|
Instance |
BusApplication |
Statyczny singleton |
Is365 |
bool |
true = wersja HTML, false = wersja okienkowa |
this[string] |
Database |
Indeksator - baza po nazwie |
Database
Abstrakcyjna klasa reprezentująca bazę danych. Konkretne implementacje dla wspieranych silników:
Database (abstrakcyjna)
└── SqlDatabase (abstrakcyjna)
├── MsSqlDatabase (SQL Server)
└── AzureDatabase (Azure SQL)
Uwaga: MySqlDatabase oraz OracleDatabase nie są już obsługiwane.
Konfiguracja
Obiekty Database są deserializowane z pliku Lista baz danych.xml.
Właściwości
| Właściwość | Typ | Opis |
|---|---|---|
Name |
string |
Nazwa bazy danych |
DefaultDatabase |
bool |
Czy baza domyślna |
DatabaseName |
string |
Nazwa bazy w silniku SQL (SqlDatabase) |
Logowanie do bazy
Database db = BusApplication.Instance["BazaDemo"];
// ZALECANE: Logowanie z LoginParameters
Login login = db.Login(new LoginParameters
{
UserName = "Administrator",
UserPassword = "password"
});
// Logowanie zintegrowane Windows
Login login = db.Login(new LoginParameters
{
UserName = LoginParameters.WindowsAuthenticationUser
});
Login
Obiekt reprezentujący zalogowanego użytkownika. Zarządza sesjami.
Tworzenie
Database db = BusApplication.Instance["BazaDemo"];
Login login = db.Login(new LoginParameters
{
UserName = "Administrator",
UserPassword = "password"
});
Dostęp do informacji o operatorze
WAŻNE: Właściwości Operator i Entitle w klasie Login nie należy stosować, ponieważ używają obiektu z ConfigSession w sposób niekontrolowany.
// NIE ZALECANE:
// var op = login.Operator; // unikać!
// var ent = login.Entitle; // unikać!
// ZALECANE: Użyj w konkretnej sesji
using (var session = login.CreateSession(true, false, "Odczyt"))
{
var op = session.AuthorizationInfo.Operator;
Console.WriteLine($"Zalogowany: {op.Name} - {op.FullName}");
}
Właściwości informacyjne
| Właściwość | Typ | Opis |
|---|---|---|
IsWebUser |
bool |
Czy operator pulpitu (web) |
Licencje |
IEnumerable |
Pobrane licencje |
Database |
Database |
Baza danych logowania |
Tworzenie sesji
// ZALECANA sygnatura (czytelność + debugowanie)
Session session = login.CreateSession(
readOnly: false, // true = tylko odczyt
config: false, // true = dane konfiguracyjne
name: "MojaSesja" // nazwa sesji - pomocna przy debugowaniu
);
Zawsze używaj wersji z parametrem name - ułatwia debugowanie i identyfikację sesji.
Dostęp do danych konfiguracyjnych
// ZALECANE: ExecuteConfig z lambdą (zwraca wartość prostą)
var opisDlaSzt = login.ExecuteConfig(configSession =>
configSession.GetTowary().Jednostki.WgKodu["szt"]?.Opis);
// NIE ZALECANE: login.ConfigSession
// var configSession = login.ConfigSession; // unikać!
WAŻNE: Używając ExecuteConfig() nie można zwracać obiektów sesyjnych z sesji konfiguracyjnej, ponieważ może być używana w innym wątku do innych celów. Zwracaj tylko wartości proste lub kopie danych.
Sygnatury CreateSession
public Session CreateSession(bool readOnly, bool config, string name)
public Session CreateSession(bool readOnly, bool config)
public Session CreateSession() // readOnly=false, config=false
Session
Fundamentalna klasa do zarządzania danymi. Każda operacja na danych wymaga sesji.
Tworzenie
// ZAWSZE używaj using lub wywołuj Dispose()
using (var session = login.CreateSession(false, false, "MojaSesja"))
{
// operacje na danych
session.Save();
}
Typy sesji - macierz
| ReadOnly | Config | Zastosowanie |
|---|---|---|
false |
false |
Edycja operacyjna - dokumenty, kartoteki |
true |
false |
Odczyt operacyjny - raporty, wyświetlanie |
false |
true |
Edycja konfiguracyjna - ustawienia systemu |
true |
true |
Odczyt konfiguracyjny - odczyt słowników |
WAŻNE: W sesji operacyjnej (config: false) nie można modyfikować obiektów konfiguracyjnych. Do modyfikacji konfiguracji wymagana jest sesja konfiguracyjna (config: true).
Właściwości
| Właściwość | Typ | Opis |
|---|---|---|
ReadOnly |
bool |
Czy sesja tylko do odczytu |
IsConfig |
bool |
Czy sesja konfiguracyjna |
Name |
string |
Nazwa sesji |
Login |
Login |
Obiekt logowania |
Database |
Database |
Baza danych |
Metody zarządzania danymi
// Zapisanie zmian do bazy
session.Save();
Dane operacyjne vs konfiguracyjne
Dane operacyjne (config=false):
- Dokumenty, kartoteki, transakcje
- Zawsze odczytywane z bazy (aktualność)
- Modyfikacje zapisywane natychmiast przy
Save()
Dane konfiguracyjne (config=true):
- Słowniki, definicje, ustawienia
- Buforowane w cache (optymalizacja)
- Modyfikowane rzadko, odczytywane często
- Określane atrybutem
config="true"w business.xml
Wiele sesji jednocześnie
// Normalne zjawisko - wiele sesji może współistnieć
using (var session1 = login.CreateSession(true, false, "Lista1"))
using (var session2 = login.CreateSession(true, false, "Lista2"))
{
// Obie sesje mogą odczytywać te same dane
var tm1 = session1.GetTowary();
var tm2 = session2.GetTowary();
}
Transakcje biznesowe - Session.Logout()
WAŻNE: Każda zmiana obiektu biznesowego MUSI być w transakcji!
using (var session = login.CreateSession(false, false, "Edycja"))
{
var tm = session.GetTowary();
var towar = tm.Towary.WgKodu["KOD001"];
// Logout(editMode: true) - transakcja EDYCYJNA (można modyfikować)
using (var transaction = session.Logout(editMode: true))
{
towar.Nazwa = "Nowa nazwa";
var cena = towar.Ceny["Hurtowa"];
cena.Netto = new DoubleCy(100.00m);
transaction.Commit(); // Zatwierdza zmiany w sesji
}
// Brak Commit() = rollback (przywrócenie stanu sprzed Logout)
session.Save(); // Zapisuje do bazy danych
}
Logout(editMode: false) - transakcja tylko do odczytu
using (var session = login.CreateSession(false, false, "Przeglad"))
{
var tm = session.GetTowary();
var towar = tm.Towary.WgKodu["KOD001"];
// Transakcja tylko do odczytu
using (var readTrans = session.Logout(editMode: false))
{
// Tutaj NIE można modyfikować
// Ale można otworzyć zagnieżdżoną transakcję edycyjną
using (var editTrans = session.Logout(editMode: true))
{
var cena = towar.Ceny["Hurtowa"];
cena.Netto = new DoubleCy(200m);
editTrans.Commit();
}
// WAŻNE: Commit wymagany też dla transakcji readonly!
// Inaczej zmiany z zagnieżdżonych transakcji edycyjnych przepadną
readTrans.Commit();
}
session.Save();
}
| Metoda | Opis |
|---|---|
session.Logout(editMode: true) |
Transakcja edycyjna - można modyfikować |
session.Logout(editMode: false) |
Transakcja tylko do odczytu |
transaction.Commit() |
Zatwierdza zmiany (wymagane dla obu typów!) |
transaction.CommitUI() |
Zatwierdza + odświeża UI |
transaction.Dispose() |
Bez Commit = rollback (także zagnieżdżonych zmian) |
Kompletny przykład
// 1. Pobranie instancji aplikacji
BusApplication app = BusApplication.Instance;
// 2. Pobranie bazy danych
Database db = app["MojaBaza"];
// 3. Logowanie
Login login = db.Login(new LoginParameters
{
UserName = "admin",
UserPassword = "haslo"
});
// 4. Utworzenie sesji (zawsze z nazwą!)
using (var session = login.CreateSession(false, false, "Import"))
{
// 5. Pobranie modułu (extension method)
var tm = session.GetTowary();
// 6. Transakcja biznesowa - WYMAGANA dla zmian!
using (var transaction = session.Logout(editMode: true))
{
var nowyTowar = new Towar();
tm.Towary.AddRow(nowyTowar);
nowyTowar.Kod = "IMPORT001";
nowyTowar.Nazwa = "Zaimportowany towar";
transaction.Commit();
}
// 7. Zapis do bazy
session.Save();
}
// 8. Session automatycznie Dispose() przez using
Thread-safety
Obiekty multi-threaded (można współdzielić między wątkami)
BusApplicationDatabaseLogin
Obiekty single-threaded (NIE współdzielić)
Session,Module,Table,Row,Context
// DOBRZE - Login można współdzielić, każdy wątek tworzy własną sesję
Login sharedLogin = db.Login(new LoginParameters { UserName = "admin", UserPassword = "haslo" });
Parallel.ForEach(items, item => {
using (var session = sharedLogin.CreateSession(false, false, "Watek"))
{
var tm = session.GetTowary();
using (var transaction = session.Logout(editMode: true))
{
// operacje...
transaction.Commit();
}
session.Save();
}
});
Sesja bez interfejsu graficznego
Sesja działa w warstwie logiki biznesowej - nie wymaga UI.
Przykłady użycia bez interfejsu:
- Harmonogram Zadań - usługa Windows wykonująca operacje bazodanowe
- Importy danych - procesy wsadowe
- Testy jednostkowe - automatyczne testy logiki
- API REST - obsługa żądań HTTP