CRUD

TsgcHTMLComponent_CRUD: de lijst, zoekfunctie, paginering, het formulier voor aanmaken en bewerken, de bevestiging van verwijderen en het schrijfpad van één tabel als één component, op basis van een TDataSet of je eigen SQL, in Delphi, C++ Builder en .NET.

TsgcHTMLComponent_CRUD

De pagina die elke bedrijfsapplicatie voor elke tabel opnieuw schrijft, als één component. Geef het een sleutelveld en een routeprefix, koppel dan een TDataSet of geef het een adapter met zes methoden voor je eigen SQL. ShowList levert de markup, en wat de pagina terugpost gaat via ProcessAction.

Componentklasse

TsgcHTMLComponent_CRUD, met TsgcHTMLCRUDAdapter en TsgcHTMLCRUDAdapter_DataSet in dezelfde unit

Rendert

De lijst met zoekfunctie en paginering, het formulier voor aanmaken en bewerken en de bevestiging van verwijderen

Talen

Delphi, C++ Builder, .NET

Koppel een dataset, of schrijf de adapter

Stel KeyField en RoutePrefix in, koppel een actieve DataSet en roep ShowList(search, page) aan. Voor je eigen SQL geef je het component in plaats daarvan een adapter met SetAdapter. Stuur wat de pagina terugpost door naar 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

Belangrijkste eigenschappen en methoden

De members die je het vaakst gebruikt.

Adapter

TsgcHTMLCRUDAdapter is het schrijfpad, met zes virtuele methoden: Locate, Read, List, Insert, Update en Delete. TsgcHTMLCRUDAdapter_DataSet stuurt de gekoppelde dataset aan, en SetAdapter geeft het component een eigen adapter mee en neemt er de eigendom van over. List levert één pagina als door tabs gescheiden regels, met de sleutel als laatste cel, en geeft terug hoeveel rijen de hele set heeft.

In .NET

Er is geen TDataSet, dus de port levert drie adapters mee: TsgcHTMLCRUDAdapter_DataTable voor een DataTable, TsgcHTMLCRUDAdapter_List<T> voor elke IList<T> en TsgcHTMLCRUDAdapter_DbConnection voor een tabel achter een DbConnection, waarbij elke waarde als parameter wordt verstuurd. Declareer de Columns: ze worden niet uit de tabel gelezen.

De pagina

ShowList(search, page), ShowNew, ShowEdit(key), Save(key, values, html) en DeleteRecord(key, html) leveren elk de markup die de host in de pagina swapt. ProcessAction stuurt de geposte crudList, crudNew, crudEdit, crudSave en crudDelete naar deze methoden door en antwoordt met False voor elke andere actie, zodat een pagina meerdere componenten kan bevatten.

Pagina-opties

Actions is een set van caCreate, caEdit, caDelete, caView en caExport, en een pagina met alleen caView is een rapport. EditMode is cemModal of cemPage, ConfirmDelete vraagt bevestiging voor een verwijdering, PageSize is standaard 25 en gaat nooit boven 500, en SearchFields somt de velden op waarin het zoekvak zoekt, gescheiden door puntkomma's.

Kolommen

Een TsgcHTMLCRUDColumn heeft FieldName, Caption, Visible, ReadOnly, Required, InList, InForm, Width en MaxLength. Als er geen zijn gedeclareerd, leest het component ze uit de actieve dataset: de titel uit DisplayLabel, de vlag voor verplichte velden en de lengte, en de sleutel wordt getoond maar nooit bewerkt. LoadColumnsFromDataSet doet dat op verzoek.

Validatie

Een verplichte kolom die leeg is en een waarde die langer is dan MaxLength worden eerst geweigerd. Daarna wordt OnValidate aangeroepen: voeg per probleem een regel toe aan aErrors en er wordt niets geschreven, het formulier komt terug met de berichten. OnApplyUpdates draait vóór de adapter, en als je aHandled instelt, neem jij het schrijven over. OnApplied treedt op nadat een schrijfactie is gelukt, om die te loggen of om iedereen te vernieuwen die de lijst bekijkt.

Optimistische vergrendeling

Geef in VersionField een versieveld op. Bij het opslaan wordt vergeleken wat de browser verstuurt met wat is opgeslagen, en de schrijfactie wordt geweigerd als iemand anders het record in de tussentijd heeft gewijzigd, zodat de tweede persoon die op Save drukt de eerste niet overschrijft.

Master en detail

Details bevat de onderliggende lijsten van een record. Elk item noemt een ander TsgcHTMLComponent_CRUD in CRUD, het veld van de onderliggende lijst dat de mastersleutel bevat in MasterField, en een Caption. Ze worden onder het formulier gerenderd terwijl een record wordt bewerkt. SetMaster(field, value) beperkt een lijst tot één masterrecord.

CSV-export

Met caExport toont de werkbalk een Export-link naar RoutePath('export.csv'). Beantwoord die route met GetExportCSV(search): die exporteert de zoekresultaten die de lijst toont, tot 500 rijen, niet de hele tabel. Elke waarde staat tussen aanhalingstekens, zodat een komma of een regeleinde het bestand niet kan breken.

De sleutel wordt eerst opgezocht

Elke sleutel komt van de browser. ShowEdit, Save en DeleteRecord vragen de adapter die sleutel met Locate op te zoeken voordat er iets wordt bewerkt of verwijderd, zodat het wijzigen van een getal in een URL nooit een ander record bereikt. Actions wordt ook afgedwongen: een pagina zonder caDelete weigert een verwijdering, ook als een vervalst formulier er een post. Cellen en velden worden geëscaped, zodat een record dat markup bevat als tekst wordt getoond.

Socket en HTTP

Het zoekvak, New, Edit, Delete en het formulier zijn formulieren met de markering data-sgc-ws-send, elk met verborgen velden action, crud en key, en de host geeft ze door aan ProcessAction. Een bericht via de socket bevat geen pad en bereikt de router nooit, dus autoriseer het zelf. In Delphi geeft TsgcHTMX_Engine_Server.MessageSession de sessie achter de handshake-cookies terug, of nil. Voor HTTP bouwt RoutePath de paden die een host declareert op de router van de engine: /customers, /customers/new, /customers/{id}/edit, /customers/save en /customers/{id}/delete.

Manieren om te beginnen

Maak het in code aan, zoals hierboven, of gebruik de wizard in de Delphi IDE: Tools › New sgcHTML CRUD page toont de datasets op het geopende formulier, leest de velden van de dataset die je kiest en voegt een geconfigureerd component aan het formulier toe, met de twee regels voor de koppeling op het klembord. Delphi 10.4 of later is vereist. Buiten de IDE schrijft het opdrachtregelprogramma sgcHTMLGen de broncode van de pagina in Object Pascal of in C#, op basis van de tabel, het routeprefix en de velden, elk geschreven als name:flag, bijvoorbeeld ID:key of NAME:req:60.

Beschikbaarheid

Onderdeel van sgcHTML, dat los van sgcWebSockets wordt verkocht. De unit compileert waar SGC_HTML is gedefinieerd, wat sgcVer.inc doet voor het HTML-pack op elk platform behalve Android en iOS. De demo is Demos\60.HTML\01.RunTime\02.AdminCRUD, waarin het klantengedeelte is gebouwd op dit component, naast de met de hand geschreven pagina die het verving.

Blijf ontdekken

Online helpGebruikshandleiding voor CRUD-pagina's, de adapter en het schrijfpad.
Alle sgcHTML-componentenBlader door de volledige functiematrix van 80+ componenten.
Download gratis proefversieDe proefversie van 30 dagen bevat de 60.HTML-demoprojecten.
PrijzenSingle-, Team- en Site-licenties met volledige broncode.
De beste deal: All-AccessElk eSeGeCe-product, inclusief Premium-ondersteuning, vanaf €1,059 per jaar.
Bekijk de All-Access-prijzen

Klaar om te beginnen?

Download de gratis proefversie en begin met het bouwen van web-UI's in Delphi, C++ Builder en .NET.