Pisanie logiki biznesowej w C# dla wersji starszych niż 6.0¶
Zasady ogólne¶
W Neosie starszym niż wersja 5.4 w ogóle nie ma podziału na metody logiki biznesowej i metody interfejsu. Zatem kod logiki biznesowej piszemy, albo w bazie danych, albo w metodach obiektów biznesowych, używając:
- programowych źródeł danych (czyli np.
var klienci = new COMMON.KLIENCI();) - bezpośredniego dostępu do bazy danych (czyli np.
var dv = DB.OpenTable(...))
W wersji 5.4 pojawił się podział na metody logiki biznesowej i metody interfejsu, dlatego od tej wersji należy kod sterujący interfejsu pisać w metodach interfejsu, a kod logiki pisać w metodach logiki biznesowej. Od tej wersji nie ma już dostępu do klasy statycznej DB, ale jest podział na klasę GUI dla metod statycznych interfejsu (np. GUI.ShowForm(...)) oraz CORE dla metod statycznych logiki biznesowej, np (CORE.OpenTable(...)). W dalszym ciągu kod logiki biznesowej piszemy używając:
- programowych źródeł danych (czyli np.
var klienci = new COMMON.KLIENCI();) - obiekt z dostępem do bieżącego rekordu, pól modelu danych, możliwością chodzenia po rekordach, itp. - programowych źródeł danych logiki (czyli np.
var klienci = new LOGIC.COMMON.KLIENCI();) - obiekt z dostępem do metod logiki biznesowej, ale nie posiadający tzw. bieżącego rekordu i możliwości iterowania po rekordach - bezpośredniego dostępu do bazy danych (czyli np.
var dv = CORE.OpenTable(...)lubvar dv = CORE.QuerySQL(...))
Zaleca się jak najmniej pisać wyrażeń SQL-owych, jeśli posiadamy odpowiednie obiekty biznesowe do tych struktur danych.
Kod metody logiki biznesowej działa w jednej transakcji, rozpoczynanej przy pierwszym wejściu do kodu logiki biznesowej i commitowanej po zakończeniu metody logiki. W metodach interfejsowych każda linijka kodu, jeśli wywołuje metodę logiki, to działa w osobnej transakcji.
Wyszukiwanie danych¶
Podczas pisania kodu logiki częstym przypadkiem użycia jest przejrzenie tylko wybranych danych lub znalezienie konkretnego rekordu. Używamy w tym celu metody FilterAndSort(...) a nie FindRecord(...), po to aby rekord znaleźć poprzez dobrze ograniczone zapytanie SQL do bazy danych, a nie poprzez przeszukiwania dziedziny w pamięci komputera.
var stanyil = new STANYIL();
stanyil.FilterAndSort("KTM='" + ktm + "'");
if(stanyil.FirstRecord())
do
{
...
}
while(stanyil.NextRecord());
stanyil.Close();
Do znalezienia jednego rekordu wystarczy użyć if(stanyil.FirstRecord()) bez pętli do ... while, ale wtedy filtr powinien być napisany tak, aby na pewno zwrócić co najwyżej jeden rekord - czyli najepiej używać filtru na pola klucza głównego.
var klienci = new KLIENCI();
klienci.FilterAndSort("REF=" + klient);
if(klienci.FirstRecord())
{
...
}
klienci.Close();
Wyszukiwanie danych - dostęp bezpośredni do bazy danych¶
Kod piszemy analogicznie, jeśli nie używamy obiektów biznesowych a bezpośredniego dostępu do bazy danych. Wtedy zamiast powoływać obiekt biznesowy używamy metody OpenTable(...):
var dv = DB.OpenTable("STANYIL",""); //od wersji 5.4 to będzie CORE.OpenTable(...)
if(dv!=null) //warto sprawdzić, bo jak zapytanie będzie błędne, to dv = null
{
dv.FilterAndSort("KTM='" + ktm + "'");
if(dv.FirstRecord())
do
{
...
}
while(dv.NextRecord());
dv.Close(); //obowiązkowe, bo jak tego nie zrobimy, to zjemy cały RAM!!! Robi to samo, co DB.CloseTable(...).
}
Bardziej współczesny kod, bez pętli while napiszemy korzystając z metody QuerySQL(...) dostępnej od wersji 5.4:
foreach(var stanyil in CORE.QuerySQL("select * from STANYIL where ...")) //rzuca wyjątek w przypadku błędu SQL
{
...
}
Dodawanie rekordów¶
Aby dodać nowy rekord stosujemy sekwencję NewRecord(); ... PostRecord(); w sposób taki jak podano niżej:
var klienci = new KLIENCI();
klienci.NewRecord();
klienci.FSKROT = "ABC";
...
klienci.PostRecord(true, true); //pierwszy parametr=true gwarantuje, że rekord będzie w dziedzinie po dodaniu, drugi=true, że błąd spowoduje wyjątek a nie zwrócenie false
...
klienci.Close();
Można oczywiście wywołać bezparametryczne PostRecord(), ale należy pamiętać, że nie mamy wtedy gwarancji, że nowo dodany rekord będzie bieżącym w dziedzinie, a ewentualny błąd podczas dodawania rekordu do bazy danych nie zakończy się wyjątkiem, ale zwróceniem false. Pozwala nam co w indywidualny sposób obsłużyć błąd dodania rekordu do bazy danych. Przykład:
var klienci = new KLIENCI();
klienci.NewRecord();
klienci.FSKROT = "ABC";
...
if(!klienci.PostRecord())
{
//nie udało się dodać klienta
}
...
klienci.Close();
Edycja rekordu¶
Aby zmodyfikować uprzednio znaleziony rekord bieżący, stosujemy sekwencję EditRecord(); ... PostRecord(); na przykład tak:
var klienci = new KLIENCI();
klienci.FilterAndSort("REF=" + klient);
if(klienci.FirstRecord())
{
klienci.EditRecord();
klienci.UWAGI = "ABC";
...
klienci.PostRecord(true, true); //pierwszy parametr=true gwarantuje, że rekord będzie w dziedzinie po dodaniu, drugi=true, że błąd spowoduje wyjątek a nie zwrócenie false
}
klienci.Close();
Pamiętamy, aby edytować rekord dopiero po jego udanym znalezieniu, czyli dopiero wtedy, kiedy mamy pewność, jaki rekord edytujemy. Parametry metody PostRecord(...) stosujemy analogicznie jak podczas dodawania rekordu. Przykład z bezparametrycznym PostRecord():
var klienci = new KLIENCI();
klienci.FilterAndSort("REF=" + klient);
if(klienci.FirstRecord())
{
klienci.EditRecord();
klienci.UWAGI = "ABC";
...
if(!klienci.PostRecord())
{
//nie udało się zaktualizować danych klienta o refie w zmiennej "klient"
}
}
klienci.Close();
Usuwanie rekordu¶
Aby usunąć uprzednio znaleziony rekord bieżący, stosujemy metodę DeleteRecord() na przykład tak:
var klienci = new KLIENCI();
klienci.FilterAndSort("REF=" + klient);
if(klienci.FirstRecord())
{
if(!klienci.DeleteRecord())
{
//coś poszło nie tak, bo nie udało się usunąć
}
}
klienci.Close();
Zamykanie źródła danych¶
We wszystkich powyższych przykładach programowe źródło danych jest zamykane jawnie poprzez wywołanie metody Close(). Pozwala to na szybkie zwolnienie zasobów zajętych przez źródło danych, głównie pamięć RAM z buforem na dane. Jeśli nie wywołamy metody Close() to:
- jeśli kod napisaliśmy w obiektach biznesowych Neosa, to nie ma wielkiego dramatu, gdyż po zakończeniu obsługi bieżącego komunikatu od aplikacji klienckiej Neos sam sprząta powołane chwilę wcześniej programowe źródła danych.
- jesli kod napisaliśmy w pluginie, to bufory na dane nie są sprzątane automatycznie i nastąpi przyrost zużycia pamięci RAM, a w efekcie crash serwera Neos.
Jawne wywołanie Close() powoduje, że kod jest czystszy i programista daje jasny znak, w którym momencie dany obiekt nie będzie już potrzebny do użycia. Dlatego zaleca się używać go zawsze.