CRUD

TsgcHTMLComponent_CRUD: lista, wyszukiwanie, paginacja, formularz tworzenia i edycji, potwierdzenie usunięcia oraz ścieżka zapisu jednej tabeli w postaci jednego komponentu, działającego na TDataSet lub na własnym SQL, w Delphi, C++ Builder i .NET.

TsgcHTMLComponent_CRUD

Strona, którą każda aplikacja biznesowa pisze od nowa dla każdej tabeli, jako jeden komponent. Podaj pole klucza i prefiks trasy, a następnie powiąż TDataSet albo przekaż mu adapter z sześcioma metodami nad własnym SQL. ShowList zwraca znaczniki, a to, co strona odsyła, trafia do ProcessAction.

Klasa komponentu

TsgcHTMLComponent_CRUD, wraz z TsgcHTMLCRUDAdapter i TsgcHTMLCRUDAdapter_DataSet w tej samej jednostce

Renderuje

Lista z wyszukiwaniem i paginacją, formularz tworzenia i edycji oraz potwierdzenie usunięcia

Rodzina

Dane i tabele

Języki

Delphi, C++ Builder, .NET

Powiąż zestaw danych albo napisz adapter

Ustaw KeyField i RoutePrefix, powiąż aktywny DataSet i wywołaj ShowList(search, page). Dla własnego SQL przekaż komponentowi adapter za pomocą SetAdapter. To, co strona odsyła, kieruj przez ProcessAction.

uses
  Classes, sgcHTML_Component_CRUD;

var
  oCRUD: TsgcHTMLComponent_CRUD;
  vHTML: string;
begin
  oCRUD := TsgcHTMLComponent_CRUD.Create(nil);
  try
    oCRUD.CRUDID := 'customers';
    oCRUD.Title := 'Customers';
    oCRUD.RoutePrefix := '/customers';
    oCRUD.KeyField := 'ID';
    oCRUD.PageSize := 15;
    oCRUD.Actions := [caCreate, caEdit, caDelete, caView, caExport];
    oCRUD.VersionField := 'UPDATED_AT';   // optimistic locking
    oCRUD.OnValidate := CustomersValidate;

    // an active dataset: the columns are read off it
    oCRUD.DataSet := qryCustomers;

    vHTML := oCRUD.ShowList('', 1);   // search text, page number
  finally
    oCRUD.Free;
  end;
end;

// The rules that are about your data. Add a line per problem: nothing is
// written and the form comes back with the messages.
procedure TServer.CustomersValidate(Sender: TObject;
  aOperation: TsgcHTMLCRUDOperation; const aKey: string;
  aValues, aErrors: TStrings);
begin
  if Length(Trim(aValues.Values['NAME'])) < 3 then
    aErrors.Add('The name needs at least three characters.');
end;

// A message from the browser carries action, crud and key with the form fields
if oCRUD.ProcessAction(vAction, vKey, oFields, vHTML) then
  aResponse := vHTML;   // the markup to swap into the page

// Or over your own SQL: an adapter of six methods
type
  TCustomersAdapter = class(TsgcHTMLCRUDAdapter)
  public
    function Locate(const aKey: string): Boolean; override;
    function Read(const aKey: string; aValues: TStrings): Boolean; override;
    function List(const aSearch: string; aPage, aPageSize: Integer;
      aRows: TStrings): Integer; override;
    function Insert(aValues: TStrings; var aKey: string;
      aErrors: TStrings): Boolean; override;
    function Update(const aKey: string; aValues, aErrors: TStrings): Boolean;
      override;
    function Delete(const aKey: string; aErrors: TStrings): Boolean; override;
  end;

oCRUD.SetAdapter(TCustomersAdapter.Create(oCRUD));   // the component owns it
// includes: sgcHTML_Component_CRUD.hpp

TsgcHTMLComponent_CRUD *oCRUD = new TsgcHTMLComponent_CRUD(NULL);
try
{
  oCRUD->CRUDID = "customers";
  oCRUD->Title = "Customers";
  oCRUD->RoutePrefix = "/customers";
  oCRUD->KeyField = "ID";
  oCRUD->PageSize = 15;
  oCRUD->Actions = TsgcHTMLCRUDActions() << caCreate << caEdit << caDelete
    << caView << caExport;
  oCRUD->VersionField = "UPDATED_AT";   // optimistic locking
  oCRUD->OnValidate = CustomersValidate;

  // an active dataset: the columns are read off it
  oCRUD->DataSet = qryCustomers;

  String html = oCRUD->ShowList("", 1);   // search text, page number
}
__finally
{
  delete oCRUD;
}

// The rules that are about your data. Add a line per problem: nothing is
// written and the form comes back with the messages.
void __fastcall TServer::CustomersValidate(TObject *Sender,
  TsgcHTMLCRUDOperation aOperation, const String aKey,
  TStrings *aValues, TStrings *aErrors)
{
  if (aValues->Values["NAME"].Trim().Length() < 3)
    aErrors->Add("The name needs at least three characters.");
}

// A message from the browser carries action, crud and key with the form fields
String html;
if (oCRUD->ProcessAction(action, key, fields, html))
  response = html;   // the markup to swap into the page

// For your own SQL, derive from TsgcHTMLCRUDAdapter, override its six methods
// (Locate, Read, List, Insert, Update, Delete) and call oCRUD->SetAdapter().
using System.Collections.Generic;
using esegece.sgcWebSockets;

var crud = new TsgcHTMLComponent_CRUD();
crud.CRUDID = "customers";
crud.Title = "Customers";
crud.RoutePrefix = "/customers";
crud.KeyField = "ID";
crud.PageSize = 15;
crud.Actions = TsgcHTMLCRUDActions.caCreate | TsgcHTMLCRUDActions.caEdit
    | TsgcHTMLCRUDActions.caDelete | TsgcHTMLCRUDActions.caView
    | TsgcHTMLCRUDActions.caExport;
crud.VersionField = "UPDATED_AT";   // optimistic locking

// The key travels with the page: it is in neither the list nor the form
var id = crud.Columns.Add();
id.FieldName = "ID";
id.InList = false;
id.InForm = false;

var name = crud.Columns.Add();
name.FieldName = "NAME";
name.Caption = "Name";
name.Required = true;
name.MaxLength = 120;

// There is no TDataSet: read a DataTable, an IList<T> or a table behind a DbConnection
crud.SetAdapter(new TsgcHTMLCRUDAdapter_DataTable(crud, customersTable));

// The rules that are about your data
crud.OnValidate += (object sender, TsgcHTMLCRUDOperation op, string recordKey,
    List<string> values, List<string> errors) =>
{
    if (TsgcHTMLComponent_CRUD.ValueOf(values, "NAME").Trim().Length < 3)
        errors.Add("The name needs at least three characters.");
};

string html = crud.ShowList("", 1);   // search text, page number

// A message from the browser carries action, crud and key with the form fields
if (crud.ProcessAction(action, key, fields, out string reply))
    response = reply;   // the markup to swap into the page

Kluczowe właściwości i metody

Składniki, po które sięgasz najczęściej.

Adapter

TsgcHTMLCRUDAdapter to ścieżka zapisu, z sześcioma metodami wirtualnymi: Locate, Read, List, Insert, Update i Delete. TsgcHTMLCRUDAdapter_DataSet obsługuje powiązany zestaw danych, a SetAdapter przekazuje komponentowi Twój własny adapter i przejmuje go na własność. List zwraca jedną stronę jako linie rozdzielone tabulatorami, z kluczem w ostatniej komórce, oraz liczbę wierszy całego zbioru.

W .NET

W .NET nie ma TDataSet, dlatego port zawiera trzy adaptery: TsgcHTMLCRUDAdapter_DataTable nad DataTable, TsgcHTMLCRUDAdapter_List<T> nad dowolnym IList<T> oraz TsgcHTMLCRUDAdapter_DbConnection nad tabelą za DbConnection, przy czym każda wartość jest wysyłana jako parametr. Zadeklaruj Columns: nie są odczytywane z tabeli.

Strona

ShowList(search, page), ShowNew, ShowEdit(key), Save(key, values, html) i DeleteRecord(key, html) zwracają każda znaczniki, które host wstawia do strony. ProcessAction kieruje do nich odesłane akcje crudList, crudNew, crudEdit, crudSave i crudDelete, a dla każdej innej akcji zwraca False, dzięki czemu jedna strona może zawierać kilka komponentów.

Opcje strony

Actions to zbiór caCreate, caEdit, caDelete, caView i caExport, a strona z samym caView jest raportem. EditMode to cemModal lub cemPage, ConfirmDelete pyta przed usunięciem, PageSize domyślnie wynosi 25 i nigdy nie przekracza 500, a SearchFields wymienia pola, w których szuka pole wyszukiwania, oddzielone średnikami.

Kolumny

TsgcHTMLCRUDColumn ma FieldName, Caption, Visible, ReadOnly, Required, InList, InForm, Width i MaxLength. Gdy żadna nie jest zadeklarowana, komponent odczytuje je z aktywnego zestawu danych: podpis z DisplayLabel, flagę wymagalności i długość, a klucz jest pokazywany, ale nigdy edytowany. LoadColumnsFromDataSet robi to na żądanie.

Walidacja

Najpierw odrzucana jest pusta kolumna wymagana oraz wartość dłuższa niż MaxLength. Następnie wywoływane jest OnValidate: dodaj do aErrors jedną linię na każdy problem, a nic nie zostanie zapisane, formularz wróci z komunikatami. OnApplyUpdates uruchamia się przed adapterem, a ustawienie aHandled oznacza, że zapis wykonujesz Ty. OnApplied jest wywoływane po udanym zapisie, aby go zalogować lub odświeżyć widok każdemu, kto ogląda listę.

Blokowanie optymistyczne

Podaj pole wersji w VersionField. Zapis porównuje to, co wysyła przeglądarka, z tym, co jest zapisane, i odrzuca zapis, gdy w międzyczasie ktoś inny zmienił rekord, dzięki czemu druga osoba, która naciśnie przycisk zapisu, nie nadpisze zmian pierwszej.

Rekord nadrzędny i podrzędne

Details przechowuje listy podrzędne rekordu. Każda pozycja wskazuje inny TsgcHTMLComponent_CRUD w CRUD, pole rekordu podrzędnego, które przechowuje klucz nadrzędny, w MasterField, oraz Caption. Są renderowane pod formularzem podczas edycji rekordu. SetMaster(field, value) zawęża listę do jednego rekordu nadrzędnego.

Eksport CSV

Z caExport pasek narzędzi pokazuje link eksportu do RoutePath('export.csv'). Obsłuż tę trasę przez GetExportCSV(search): eksportuje ona wyszukiwanie, które pokazuje lista, do 500 wierszy, a nie całą tabelę. Każda wartość jest ujęta w cudzysłów, więc przecinek ani podział wiersza nie zepsują pliku.

Klucz jest najpierw lokalizowany

Każdy klucz przychodzi z przeglądarki. ShowEdit, Save i DeleteRecord wywołują na adapterze Locate dla tego klucza, zanim cokolwiek zostanie edytowane lub usunięte, więc zmiana numeru w adresie URL nigdy nie dotrze do innego rekordu. Actions też jest wymuszane: strona bez caDelete odrzuca usunięcie, nawet gdy fałszywy formularz je wyśle. Komórki i pola są escapowane, więc rekord zawierający znaczniki jest pokazywany jako tekst.

Gniazdo i HTTP

Pole wyszukiwania, akcje Nowy, Edytuj i Usuń oraz formularz to formularze oznaczone data-sgc-ws-send, każdy z ukrytymi polami action, crud i key, a host przekazuje je do ProcessAction. Wiadomość przez gniazdo nie niesie ścieżki i nigdy nie trafia do routera, więc zautoryzuj ją samodzielnie. W Delphi TsgcHTMX_Engine_Server.MessageSession zwraca sesję stojącą za ciasteczkami handshake lub nil. Dla HTTP RoutePath buduje ścieżki, które host deklaruje na routerze silnika: /customers, /customers/new, /customers/{id}/edit, /customers/save i /customers/{id}/delete.

Sposoby rozpoczęcia

Utwórz go w kodzie, jak powyżej, albo użyj kreatora w IDE Delphi: Tools › New sgcHTML CRUD page wypisuje zestawy danych na otwartym formularzu, odczytuje pola wybranego przez Ciebie zestawu i dodaje do formularza skonfigurowany komponent, a dwie linie podłączające trafiają do schowka. Wymaga Delphi 10.4 lub nowszego. Poza IDE narzędzie wiersza poleceń sgcHTMLGen zapisuje kod źródłowy strony w Object Pascal lub w C#, na podstawie tabeli, prefiksu trasy i pól, każde zapisane jako name:flag, na przykład ID:key lub NAME:req:60.

Dostępność

Element pakietu sgcHTML, sprzedawanego niezależnie od sgcWebSockets. Jednostka kompiluje się tam, gdzie zdefiniowano SGC_HTML, co sgcVer.inc robi dla pakietu HTML na każdej platformie z wyjątkiem Androida i iOS. Demo to Demos\60.HTML\01.RunTime\02.AdminCRUD, gdzie obszar klientów jest zbudowany na tym komponencie, obok ręcznie napisanej strony, którą zastąpił.

Poznawaj dalej

Pomoc onlinePrzewodnik użytkowania stron CRUD, adaptera i ścieżki zapisu.
Wszystkie komponenty sgcHTMLPrzejrzyj pełną matrycę funkcji 80+ komponentów.
Pobierz bezpłatną wersję próbną30-dniowa wersja próbna zawiera projekty demonstracyjne 60.HTML.
CennikLicencje Single, Team i Site z pełnym kodem źródłowym.
Najkorzystniejsza oferta: All-AccessWszystkie produkty eSeGeCe, ze wsparciem Premium w cenie, już od €1,059 rocznie.
Zobacz cennik All-Access

Gotowy, aby zacząć?

Pobierz bezpłatną wersję próbną i zacznij budować interfejsy webowe w Delphi, C++ Builder i .NET.