Eksport Import danych (Moduł DataFlow)¶
Opis¶
Moduł DataFlow to mechanizm, który przy wykorzystaniu technologi neos pozwala importować dane z plików xls i xlsx do bazy danych oraz w wersji 2.0 eksportować je do podanych formatów. Data flow korzysta z standardowych struktur do "starego" importu i jest kompatybilny z regułami do poprzedniego mechanizmu. Dodatkowa funkcjonalność to interfejs, który pozwala użytkownikowi w szybki prosty sposób przejść przez proces konfiguracji reguł i przypisywania wybranych przez siebie kolumn z Arkusza do parametrów procedury. Proces eksportu jest jeszcze prostszy.
Szybki start¶
Przygotowanie plików i konfiguracja:¶
- Kopiujemy katalog DataFlowModule z (X:\DBR\release\neos\modules\DataFlow) do katalogu Modules w swoim serwerze NEOS.
- Kopiujemy projekty z folderu Neos.Projects (Repozytorium Neos.Modules.DataFlow, branch master) do folderu projektów Neosa.
- Projekt IMPORTER do importu
- Projekt EKSPORTER do eksportu
- Projekt DATAFLOW_TESTS gdzie są przykładowe wywołania obu funkcjonalności
- Z poziomu aplikacji dodajemy repozytorium IMPORTER, które jest potrzebne do przechowywania plików, które chcemy zaimportować. Instrukcję jak poprawniekonfigurować repozytoria znajdziemy tutaj.
- Jeżeli przy eksporcie pliku planujemy pokazać go użytkownikowi aplikacji Desktop wybieramy w ramach jakiego repozytorium nastąpi transfer plików, jeżeli chcemy skorzystać z nowego również należy je dodać.
- Z poziomu aplikacji generujemy skrypt do aktualizacji bazy danych, z pomocą mechanizmu migracji.
Jak skonfigurować podstawowy import:¶
Reguły bezkontekstowe:¶
- W aplikacji Teneum z nową wstążką przechodzimy do: Zakładki Administracja -> Grupa Wymiana danych -> Reguły importu Excel. W pozostałych wersja przechodzimy tam gdzie dodawaliśmy reguły dla starego importu.
- Po kliknięciu w wyżej omawianą akcję powinno nam się ukazać okno: Definicja reguł importu Excel. Klikamy przycisk Dodaj
- W polu Opis, podajemy czego dotyczy reguła (ten opis będzie wyświetlany na liście reguł, w menu głównym aplikacji)
- Następnie klikamy zatwierdź
- Po dodaniu reguły musimy zdefiniować przynajmniej jeden wariant reguły. Aby to zrobić z okna definicji importu Excel wybieramy naszą regułę i klikamy przycisk Reguły.
- Po kliknięciu w przycisk powinno otworzyć się okienko Reguły importu
. - Klikamy przycisk Dodaj
- Uzupełniamy pole Opis (opis wariantu naszej reguły)
- Uzupełniamy pole Nr zakładki (zakładka w arkuszu z której będziemy importować dane)
- Możemy uzupełnić pole Akcja przed importem (jak sama nazwa mówi, możemy wywołać akcję z s_appini, która uruchomi się przed importem)
- Możemy uzupełnić pole Procedura przed importem (jak sama nazwa mówi, możemy wywołać procedurę z bazy danych, która uruchomi się przed importem)
- Uzupełniamy pole Procedura SQL (tutaj podajemy procedurę z bazy danych, która będzie odpowiadała za zasilenie bazy danych danymi z arkusza. Taka procedura musi mieć zdefiniowane tyle parametrów wejściowych ile jest kolumn w arkuszu z których będziemy importować dane)
- Możemy uzupełnić pole Akcja po imporcie (jak sama nazwa mówi, możemy wywołać akcję z s_appini, która uruchomi się po imporcie)
- Możemy uzupełnić pole Procedura po imporcie (jak sama nazwa mówi, możemy wywołać procedurę z bazy danych, która uruchomi się po imporcie)
- Możemy uzupełnić pole Nr wiersza pocz. (tutaj podajemy od którego wiersza mają być importowane dane, jeżeli tego nie uzupełnimy to mechanizm zaimportuje dane od początku arkusza)
- Uzupełniamy pole Sposób obsługi transakcji (to pole odpowiada za to w jaki sposób mechanizm będzie commit-ował zmiany w bazie. Uwaga: jeśli pole "Błąd przerwa import" nie jest zaznaczone, to między sposobami obsługi tranzakcji nie ma żadnej funkcjonalnej różnicy. Patrz tabelka poniżej)
- Uzupełniamy pole Błąd przerwa import (gdy to pole jest zaznaczone, to mechanizm przerwie proces na pierwszym błędnym wierszu. Dodatkowo jeśli sposób obsługi tranzakcji ustawiony jest na "Commit po regule" i uzyskamy błąd w jakimś wierszu, to nastąpi rollback wszystkich do tej pory zaimportowanych wierszy)
- Uzupełniamy pole Act? (to oznacza że wariant jest act i dzięki temu jest widoczny na liście wariantów po wyborze reguły z menu głównego?)
- Możemy uzupełnić pole Tryb reguły (tutaj możemy wybrać w jakim trybie będzie działać procedura SQL do importu, jeżeli chcemy korzystać z tej opcji to nasza procedura musi mieć zdefiniowany pierwszy parametr o nazwie MODE, następnie możemy uzależnić naszą procedurę od tego parametru i w zależności co tam jest, nasza procedura może wykonać różne operacje)
- Możemy uzupełnić pole Opis parametrów (tutaj możemy podać bardziej przyjazne nazwy parametrom, które są zdefiniowane w procedurze np: W procedurze mamy parametr NRFAK, możemy go opisać jako Numer Faktury i wtedy podczas mapowania zobaczymy Numer Faktury, a nie NRFAK)
- Po uzupełnieniu wszystkich pól klikamy Zatwierdź i konfiguracja jest gotowa. Należy pamiętać żeby importy zadziałał musimy w naszej bazie mieć procedurę do importu, którą podaliśmy w konfiguracji
| Sposób obsługi transakcji | Błąd przerwa import | Zachowanie |
|---|---|---|
| Commit po wierszu | False | Importuje wszystkie wiersze pomijając wiersze z błędami. |
| Commit po regule | False | Importuje wszystkie wiersze pomijając wiersze z błędami. Commit następuje po przejściu wszystkich wierszy |
| Commit po wierszu | True | Importuje wiersze do wystąpienia pierwszego błędu. |
| Commit po regule | True | Jeżeli wystąpi błąd, to nie importuje się nic. |
Reguły kontekstowe:¶
Konfiguracja reguł kontekstowych wygląda identycznie różnica jest tylko podczas dodawania reguły, ponieważ tam musimy zaznaczyć checkbox że nasza reguła jest kontekstowa. Dzięki temu reguła kontekstowa nie pokaże się w menu głównym importu.
Korzystanie z funkcjonalności DataFlow:¶
DataFlow obsługuje dwa rodzaje reguł do importu, reguły kontekstowe i bezkontekstowe:
Reguły bezkontekstowe:¶
Są to reguły, w których procedura do importu nie powinna przyjmować parametrów, które pochodzą spoza arkusz. Taką regułę możemy wywołać w Teneum z głównego menu aplikacji (Zakładka ogólne -> Import danych -> lista reguł bezkontekstowych).
Reguła bezkontekstowa zawsze otwiera okno do mapowania, w którym możemy przypisać kolumny z arkusza do parametrów wejściowych procedury, oraz zapisać nasze mapowanie.
Następnie poprzez przycisk Importuj wywołujemy działanie mechanizmu, którego wynikiem jest okno z raportem o postępie i wyniku procedury.
Jak widać w tym przypadku podczas importu wystąpił błąd w wierszu 4-ty, po przeanalizowaniu arkusza okazało się że jedna z komórek jest uzupełniona niepoprawnie.
Reguły kontekstowe:¶
Są to reguły które wykonujemy z poziomu kodu (specjalnie przygotowanych funkcji/akcji dostosowanych do indywidualnych potrzeb). Te reguły zazwyczaj mają zdefiniowane parametry spoza arkusza oraz pozwalają na pominięcie okien interfejsu, poprzez podanie odpowiednich reguł i mapowania z poziomu kodu. Aby móc korzystać z parametrów spoza arkusza, należy przekazać je w ramach parametru staticParams w metodzie GUI.CreateImport. Najwygodniej jest przekazywać je w następujący sposób: staticParams: “
Przykładowe użycie już zdefiniowanej reguły wraz z przekazaniem do niej parametrów spoza arkusza:
public static void ImportPozZamFromXLSX(string orderID)
{
var import = GUI.CreateImport(ruleId: 3, staticParams: "KEY0="+orderID+";KEY1=CG");
import.WithOnError(HandleException);
import.ShowWizard();
}
Drugi przykład pokazuje wykorzystanie importu bez konieczności uruchamiania okna do wyboru pliku i mapowania arkusza (wykorzystując już gotowe mapowanie, które zapisaliśmy wcześniej)
public static void ImportPozZamFromXLSX(string orderID)
{
var import = GUI.CreateImport(ruleId: 3, staticParams: "KEY0="+orderID+";KEY1=CG");
import.LoadMapping(8);// ref wiersza z tabeli DEFIMPEXCELMAP
import.WithOnError(HandleException);
i = import.Build();
}
Od wersji 5.4.10 oraz 5.3.19 został dodany mechanizm umożliwiający wpływanie na treść komunikatu wyjątku. Przy pomocy metody WithExceptionMessageHandler można przekazać odpowiednio utworzoną funkcję.
Przykład funkcji, która wyciąga treść wyjątku rzucanego z bazy:
public Neos.Core.Interop.Interfaces.Import.IImportProcessException ProcessException(Neos.Core.Interop.Interfaces.Import.IImportProcessException importException)
{
string message;
if(importException.InnerException!=null)
{
message = importException.InnerException.Message;
}
else
{
message = importException.Message;
}
var brtag = "\r\n";
if (message.Contains(brtag))
{
var start = message.IndexOf(brtag)+brtag.Length;
var length = message.LastIndexOf(brtag) - start;
message = message.Substring(start, length);
}
return importException.WithMessage(message);
}
Sposób przekazania:
public void RunImport()
{
var import = GUI.CreateImport(ruleId: 12, variantId: 1);
import.WithOnError(HandleException).WithExceptionMessageHandler(ProcessException).ShowWizard();
}
Import bez okna mapowania¶
Możliwe jest stworzenie własnego okna importu bez ręcznego ustawiania mapowania, w tym celu należy stworzyć regułę kontekstową oraz formę neosową, która będzie zawierać akcję importu i metodę wykonawczą:
public void ImportWithoutManualMapping()
{
/*
ruleId - REF reguły z tabeli DEFIMPEXCEL
variantId - REF wariantu reguły importu z DEFIMPEXCELPOS
_localfilepath - ścieżka do pliku z którego importujemy
mapId - REF mapowania z tabeli DEFIMPEXCELMAP (możemy stworzyć takie mapowanie za pomocą metody import.SaveMapping())
*/
var import = GUI.CreateImport(ruleId, variantId);
import.WithFile(_localfilepath);
import.LoadMapping(mapId);
import.Build().Execute();
}
Jak skonfigurować podstawowy eksport:¶
Gdy już mamy załadowany nowy moduł DataFlow, tworzymy obiekt który skonfiguruje nam eksport
var exportBuilder = GUI.CreateExportProcessBuilder();
//w 4.6.35
var exportBuilder = API.CreateExportProcessBuilder();
Potem musimy podać dane jakie zostaną wyeksportowane:
//możemy wyeksportować dane bezpośrednio z zapytania w metodzie logiki biznesowej
var sql = CORE.QuerySQL("select * from expimp");
exportBuilder.WithData(sql);
//lub zbudować arkusz od zera za pomocą API, w tym przypadku
//możemy ręcznie ustawiać format każdej komórki, używać formuł a nawet wstawiać zdjęcia
exportBuilder.WithData(FactoryMethod);
W tym drugim przypadku sami tworzymy metodę, na przykład
public void FactoryMethod(Neos.Core.Interop.Interfaces.Export.IExportDataBuilder data)
{
//możemy sterować progresem
data.TotalRows = 100005;
//możemy generować wiele arkuszy
var sheet = data.AddSheet().WithName("Arkusz 1");
var sheet2 = data.AddSheet().WithName("Arkusz 2 bo da się");
var row = sheet.AddNextRow();
row.AddNextCell().SetValue("NAZWA");
row.AddNextCell().SetValue("CENA");
row.AddNextCell().SetValue("DATA");
data.CurrentRow++;
row = sheet.AddNextRow();
//zarządzamy typami komórek
row.AddNextCell().SetValue("Towar 1");
row.AddNextCell().SetValue(4.99);
row.AddNextCell().SetValue(DateTime.Now);
data.CurrentRow++;
row = sheet.AddNextRow();
row.AddNextCell().SetValue("Towar 2");
row.AddNextCell().SetValue(12);
row.AddNextCell().SetValue(DateTime.Now);//poprawnie wstawiamy daty
data.CurrentRow++;
//możemy dodawać puste wiersze / kolumny
row = sheet.AddNextRow();
data.CurrentRow++;
//możemy używać formuł
row = sheet.AddNextRow();
row.AddNextCell().SetValue("TOTAL");
row.AddNextCell().SetFormula("sum(B1:B3)");
data.CurrentRow++;
//pętle
for(int i=0; i<100000; i++) {
row = sheet.AddNextRow();
row.AddNextCell().SetValue(i);
data.CurrentRow++;
}
//możemy wstawiać zdjęcia!
sheet2.AddPicture(@"C:\plik.png", Neos.Core.Interop.Enums.Export.PictureType.PNG, 10, 5);
data.CurrentRow++;
}
Następnie dla naszego buildera procesu należy skonfigurować parametry eksportu.
exportBuilder.WithClientPath(_clientpath); //ścieżka po stronie klienta (pamiętajmy, że przeglądarka, a więc i klient web nie ma dostępu do lokalnego filesystemu)
exportBuilder.WithShowingGeneratedFile(); //pokaż plik po wygenerowaniu (dostępne tylko pod vcl)
exportBuilder.WithRemoteApp(); //tryb RemoteApp
exportBuilder.WithServerRepository(_serverrepo); //repozytorium serwerowe plików
exportBuilder.WithServerPath(_serverfilepath); //ścieżka do pliku po stronie serwera
exportBuilder.WithFileFormat(_format); //format eksportu
exportBuilder
.WithBeforeAction((process) => Handle("OnBefore", process))
.WithAfterAction((process) => Handle("OnAfter", process))
.WithOnError((process) => Handle("OnError", process))
.WithOnFinish((process) => Handle("OnFinish", process))
.WithOnSuccess((process) => Handle("OnSuccess", process)); //akcje podpinane pod eventy
public void Handle(string message, IExportProcess process)
{
DEBUG.Log($"{message} action");
}
Na koniec możemy wybrać czy uruchamiamy Wizarda eksportu, czy od razu uruchamiamy proces
exportBuilder.ShowWizard(); //wizard
exportBuilder.Build().Execute(); //uruchomienie bez wizarda