CRUD

TsgcHTMLComponent_CRUD: l’elenco, la ricerca, la paginazione, il modulo di creazione e modifica, la conferma di eliminazione e il percorso di scrittura di una tabella in un unico componente, su un TDataSet o sul tuo SQL, in Delphi, C++ Builder e .NET.

TsgcHTMLComponent_CRUD

La pagina che ogni applicazione gestionale riscrive per ogni tabella, ridotta a un solo componente. Dagli un campo chiave e un prefisso di route, poi collega un TDataSet oppure passagli un adapter di sei metodi sul tuo SQL. ShowList risponde con il markup, e ciò che la pagina invia di ritorno passa da ProcessAction.

Classe del componente

TsgcHTMLComponent_CRUD, con TsgcHTMLCRUDAdapter e TsgcHTMLCRUDAdapter_DataSet nella stessa unit

Renderizza

L’elenco con ricerca e paginatore, il modulo di creazione e modifica e la conferma di eliminazione

Famiglia

Dati e Tabelle

Linguaggi

Delphi, C++ Builder, .NET

Collega un dataset, oppure scrivi l’adapter

Imposta KeyField e RoutePrefix, collega un DataSet attivo e chiama ShowList(search, page). Per il tuo SQL, dai invece al componente un adapter con SetAdapter. Instrada ciò che la pagina invia di ritorno tramite 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

Proprietà e metodi principali

I membri che utilizzerai più spesso.

Adapter

TsgcHTMLCRUDAdapter è il percorso di scrittura, con sei metodi virtuali: Locate, Read, List, Insert, Update e Delete. TsgcHTMLCRUDAdapter_DataSet pilota il dataset collegato, e SetAdapter passa al componente un adapter tuo e ne assume la proprietà. List risponde con una pagina sotto forma di righe separate da tabulazioni, con la chiave come ultima cella, e restituisce quante righe ha l’intero insieme.

In .NET

Non esiste TDataSet, quindi la versione .NET include tre adapter: TsgcHTMLCRUDAdapter_DataTable su un DataTable, TsgcHTMLCRUDAdapter_List<T> su qualsiasi IList<T> e TsgcHTMLCRUDAdapter_DbConnection su una tabella dietro una DbConnection, con ogni valore inviato come parametro. Dichiara le Columns: non vengono lette dalla tabella.

La pagina

ShowList(search, page), ShowNew, ShowEdit(key), Save(key, values, html) e DeleteRecord(key, html) rispondono ciascuno con il markup che l’host inserisce nella pagina. ProcessAction instrada verso di essi le azioni inviate crudList, crudNew, crudEdit, crudSave e crudDelete, e risponde False per qualsiasi altra azione, così una pagina può contenere più componenti.

Opzioni della pagina

Actions è un insieme di caCreate, caEdit, caDelete, caView e caExport, e una pagina con il solo caView è un report. EditMode è cemModal oppure cemPage, ConfirmDelete chiede conferma prima di un’eliminazione, PageSize vale 25 per impostazione predefinita e non supera mai 500, e SearchFields elenca i campi in cui cerca la casella di ricerca, separati da punti e virgola.

Colonne

Un TsgcHTMLCRUDColumn ha FieldName, Caption, Visible, ReadOnly, Required, InList, InForm, Width e MaxLength. Se non ne dichiari nessuna, il componente le legge dal dataset attivo: la didascalia da DisplayLabel, il flag di obbligatorietà e la lunghezza, e la chiave viene mostrata ma mai modificata. LoadColumnsFromDataSet lo fa su richiesta.

Validazione

Vengono rifiutati per primi una colonna obbligatoria vuota e un valore più lungo di MaxLength. Poi viene interpellato OnValidate: aggiungi una riga per ogni problema a aErrors e non viene scritto nulla, il modulo torna indietro con i messaggi. OnApplyUpdates viene eseguito prima dell’adapter e, impostando aHandled, la scrittura diventa tua. OnApplied scatta dopo che una scrittura è andata a buon fine, per registrarla nel log o aggiornare chiunque altro stia guardando l’elenco.

Locking ottimistico

Indica un campo di versione in VersionField. Un salvataggio confronta ciò che invia il browser con ciò che è memorizzato e rifiuta la scrittura se nel frattempo qualcun altro ha modificato il record, così la seconda persona che preme Salva non sovrascrive la prima.

Master e dettaglio

Details contiene gli elenchi figli di un record. Ogni elemento nomina un altro TsgcHTMLComponent_CRUD in CRUD, il campo del figlio che contiene la chiave master in MasterField e una Caption. Vengono renderizzati sotto il modulo mentre un record è in modifica. SetMaster(field, value) restringe un elenco a un solo record master.

Esportazione CSV

Con caExport la barra degli strumenti mostra un link Esporta verso RoutePath('export.csv'). Rispondi a quella route con GetExportCSV(search): esporta la ricerca che l’elenco sta mostrando, fino a 500 righe, non l’intera tabella. Ogni valore è racchiuso tra virgolette, così una virgola o un’interruzione di riga non può rompere il file.

La chiave viene localizzata per prima

Ogni chiave arriva dal browser. ShowEdit, Save e DeleteRecord chiedono all’adapter di eseguire Locate su di essa prima che qualcosa venga modificato o eliminato, così cambiare un numero in un URL non raggiunge mai un altro record. Anche Actions viene applicato: una pagina senza caDelete rifiuta un’eliminazione anche quando un modulo contraffatto ne invia una. Celle e campi vengono sottoposti a escape, così un record che contiene markup viene mostrato come testo.

Socket e HTTP

La casella di ricerca, Nuovo, Modifica, Elimina e il modulo sono moduli contrassegnati con data-sgc-ws-send, ciascuno con i campi nascosti action, crud e key, e l’host li passa a ProcessAction. Un messaggio sul socket non porta con sé alcun percorso e non raggiunge mai il router, quindi autorizzalo tu stesso. In Delphi, TsgcHTMX_Engine_Server.MessageSession risponde con la sessione associata ai cookie dell’handshake, oppure con nil. Per HTTP, RoutePath costruisce i percorsi che un host dichiara sul router dell’engine: /customers, /customers/new, /customers/{id}/edit, /customers/save e /customers/{id}/delete.

Modi per iniziare

Crealo nel codice, come sopra, oppure usa la procedura guidata nell’IDE di Delphi: Tools › New sgcHTML CRUD page elenca i dataset del form aperto, legge i campi di quello che scegli e aggiunge al form un componente già configurato, con le due righe di collegamento negli appunti. Richiede Delphi 10.4 o successivo. Fuori dall’IDE, lo strumento a riga di comando sgcHTMLGen scrive il sorgente della pagina in Object Pascal o in C#, a partire dalla tabella, dal prefisso di route e dai campi, ciascuno scritto come name:flag, ad esempio ID:key oppure NAME:req:60.

Disponibilità

Parte di sgcHTML, che si vende indipendentemente da sgcWebSockets. L’unit compila dove è definito SGC_HTML, cosa che sgcVer.inc fa per il pack HTML su tutte le piattaforme tranne Android e iOS. La demo è Demos\60.HTML\01.RunTime\02.AdminCRUD, dove l’area clienti è costruita su questo componente accanto alla pagina scritta a mano che ha sostituito.

Continua a esplorare

Guida in lineaGuida all’uso per le pagine CRUD, l’adapter e il percorso di scrittura.
Tutti i componenti sgcHTMLEsplora la matrice completa delle funzionalità di oltre 80 componenti.
Scarica la Prova GratuitaLa prova di 30 giorni include i progetti demo 60.HTML.
PrezziLicenze Single, Team e Site con codice sorgente completo.
La scelta più conveniente: All-AccessTutti i prodotti eSeGeCe, con Supporto Premium incluso, a partire da €1,059/anno.
Vedi i prezzi All-Access

Pronto a Iniziare?

Scarica la versione di prova gratuita e inizia a creare interfacce web in Delphi, C++ Builder e .NET.