Przejdź do treści

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).

xlsx_screen_1.png

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.

xlsx_screen2.png

Następnie poprzez przycisk Importuj wywołujemy działanie mechanizmu, którego wynikiem jest okno z raportem o postępie i wyniku procedury.

xlsx_screen3.png

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: “=”. Można również przekazywać same wartości po średniku. Parametry spoza arkusza w procedurze SQL powinny być zdefiniowane na samym początku.

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