Elke bedrijfsapplicatie bevat dezelfde pagina, telkens opnieuw geschreven voor elke tabel: een lijst met een zoekbalk en een pager, een formulier om aan te maken en te bewerken, een bevestiging om te verwijderen, en de code die schrijft. Onze eigen admin-demo had vier request handlers en ongeveer vierhonderd regels paginabouwers voor klanten alleen al, en dan weer hetzelfde voor leveranciers, en weer voor facturen.
sgcWebSockets 2026.10 voegt TsgcHTMLComponent_CRUD toe, dat die pagina beheert. De demo bouwt het klantenonderdeel nu met een adapter van zes methoden, en houdt de handgeschreven versie ernaast zodat je beide kunt lezen.
De pagina
uses
sgcHTML_Component_CRUD;
FCRUD := TsgcHTMLComponent_CRUD.Create(Self);
FCRUD.CRUDID := 'customers';
FCRUD.RoutePrefix := '/customers';
FCRUD.Title := 'Customers';
FCRUD.KeyField := 'ID';
FCRUD.PageSize := 15;
FCRUD.Actions := [caCreate, caEdit, caDelete, caView, caExport];
FCRUD.DataSet := FDQueryCustomers;
Gekoppeld aan een dataset leest het zijn eigen kolommen, en dat is de hele pagina: lijst, zoeken, paginering, het formulier om aan te maken en te bewerken, de verwijderbevestiging en een CSV-export van wat de lijst ook toont.
Of je eigen SQL
Een dataset is één manier om records op te slaan, niet de enige. Alles wat een record wijzigt, verloopt via een adapter, zodat het component nooit SQL, een record of een databasedriver ziet:
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;
FCRUD.SetAdapter(TCustomersAdapter.Create(FCRUD));
Zes methoden over wat je al hebt. In de demo is elke methode één enkele aanroep op de databasepool van de applicatie.
De onderdelen die je daarna zelf had geschreven
Optimistic locking. Geef een versiekolom op en een opslagactie vergelijkt wat de browser stuurt met wat is opgeslagen, zodat de tweede persoon die op Opslaan drukt te horen krijgt dat het record is gewijzigd, in plaats van de eerste stilzwijgend te overschrijven:
FCRUD.VersionField := 'UPDATED_AT';
Master en detail. De onderliggende lijsten van een record zijn andere CRUD-componenten, weergegeven onder het formulier terwijl het record wordt bewerkt:
with FCRUD.Details.Add do
begin
CRUD := FCRUDOrderLines;
MasterField := 'ORDER_ID';
Caption := 'Lines';
end;
Validatie die over je data gaat, niet over formulieren. Verplichte kolommen zijn de taak van het component; OnValidate is waar de regels over klanten thuishoren. Voeg een regel toe per probleem en het schrijven wordt geweigerd, waarna het formulier terugkomt met die regels.
Twee manieren om te beginnen
In de IDE is er nu een wizard: Tools › New sgcHTML CRUD page. Geef de tabel, de sleutel en de kolommen op, en het component wordt aangemaakt op het formulier dat je aan het ontwerpen bent, met de twee regels die het aansluiten al op het klembord.
Buiten de IDE is er een opdrachtregeltool, sgcHTMLGen, die de broncode van de pagina schrijft in Object Pascal of in C#:
sgcHTMLGen crud --table Customers --prefix /customers ^
--fields "ID:key CODE:req:32 NAME:req:120 CITY:80 NOTES:noform"
Hoe de pagina antwoordt
Elk element van de pagina post op dezelfde manier: de zoekbalk, de knop Nieuw, de Bewerken- en Verwijderenacties van een rij en het formulier zelf dragen drie verborgen velden, action, crud en, waar het iets betekent, key. De host leest ze en roept ProcessAction aan, die de markup teruggeeft die moet worden ingewisseld.
Een bericht dat over de socket wordt verzonden, draagt geen pad, dus het bereikt de router nooit en krijgt nooit de eigen controle van de router. Het autoriseren ervan is de taak van de applicatie, en de engine geeft je nu wat daarvoor nodig is:
oSession := FHTMXEngine.MessageSession(aConnection, FAuth);
try
if not Assigned(oSession) then
Exit; // a write with nobody behind it is not a write
oPage.ProcessAction(vAction, oParams.Values['key'], oParams, aResponse);
finally
oSession.Free;
end;
De sleutel die van de browser binnenkomt, wordt via Locate opgezocht voordat er geschreven wordt, zodat een sleutel die bij niemand hoort, niets schrijft.
Bekijk beide versies
In Demos\60.HTML\01.RunTime\02.AdminCRUD is /customers het component en /customers-classic de pagina die het vervangt. Dezelfde database, dezelfde data, dezelfde look. De ene is vierhonderd regels korter.
Upgraden
Het component maakt deel uit van sgcHTML en is additief: er verandert niets aan een bestaande pagina totdat je er een op een formulier plaatst.
Lees verder
- Stel je Delphi-grid een vraag in gewoon Engels
- Een gesloten browser bereiken, vanuit Delphi
- sgcWebSockets 2026.10, al het overige uit deze release
Bekijk het
Er is een korte video hierover op het eSeGeCe-kanaal.
Vragen, feedback of hulp bij migratie? Neem contact op — je krijgt antwoord van de mensen die de code hebben geschreven.
