Uma página web CRUD em Delphi em cinco minutos

· Componentes
Uma página web CRUD em Delphi em cinco minutos

Toda aplicação de negócio contém a mesma página, escrita de novo para cada tabela: uma lista com uma caixa de busca e um paginador, um formulário para criar e editar, uma confirmação de exclusão, e o código que escreve. Nosso próprio demo de administração tinha quatro manipuladores de requisição e cerca de quatrocentas linhas de construtores de página só para clientes, e depois o mesmo de novo para fornecedores, e de novo para faturas.

O sgcWebSockets 2026.10 adiciona o TsgcHTMLComponent_CRUD, que é dono dessa página. O demo agora constrói a área de clientes com um adaptador de seis métodos, e mantém a versão escrita à mão ao lado para que você possa ler as duas.

A página

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;

Vinculado a um dataset, ele lê suas próprias colunas, e isso é a página inteira: lista, busca, paginação, o formulário de criação e edição, a confirmação de exclusão e uma exportação CSV de tudo o que a lista está exibindo.

Ou o seu próprio SQL

Um dataset é uma forma de armazenar registros, não a única. Tudo o que altera um registro passa por um adaptador, então o componente nunca vê SQL, um registro ou um driver de banco de dados:

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

Seis métodos sobre o que você já tem. No demo, cada um é uma única chamada ao pool de banco de dados da aplicação.

As partes que você teria escrito depois

Bloqueio otimista. Informe uma coluna de versão e uma gravação compara o que o navegador envia com o que está armazenado, de modo que a segunda pessoa a clicar em Salvar é avisada de que o registro mudou, em vez de sobrescrever silenciosamente o primeiro:

FCRUD.VersionField := 'UPDATED_AT';

Mestre e detalhe. As listas filhas de um registro são outros componentes CRUD, renderizados sob o formulário enquanto o registro está sendo editado:

with FCRUD.Details.Add do
begin
  CRUD := FCRUDOrderLines;
  MasterField := 'ORDER_ID';
  Caption := 'Lines';
end;

Validação que é sobre os seus dados, não sobre formulários. As colunas obrigatórias são trabalho do componente; OnValidate é onde vivem as regras que são sobre os clientes. Adicione uma linha por problema e a gravação é recusada e o formulário volta com elas.

Duas formas de começar

Na IDE agora há um assistente: Tools › New sgcHTML CRUD page. Informe a tabela, a chave e as colunas, e o componente é criado no formulário em edição, com as duas linhas que o conectam já na área de transferência.

Fora da IDE há uma ferramenta de linha de comando, sgcHTMLGen, que escreve o código-fonte da página em Object Pascal ou em C#:

sgcHTMLGen crud --table Customers --prefix /customers ^
  --fields "ID:key CODE:req:32 NAME:req:120 CITY:80 NOTES:noform"

Como a página responde

Todo controle da página envia da mesma forma: a caixa de busca, o botão Novo, o Editar e o Delete de uma linha e o próprio formulário carregam três campos ocultos, action, crud e, quando faz sentido, key. O host os lê e chama ProcessAction, que responde com o markup a ser trocado.

Uma mensagem enviada pelo socket não carrega nenhum caminho, então ela nunca chega ao roteador e nunca passa pela verificação própria do roteador. Autorizá-la é trabalho da aplicação, e o motor agora entrega a você o que isso exige:

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;

A chave que chega do navegador é localizada antes de qualquer gravação ser executada, de modo que uma chave que não pertence a ninguém não grava nada.

Veja as duas versões

Em Demos\60.HTML\01.RunTime\02.AdminCRUD, /customers é o componente e /customers-classic é a página que ele substituiu. Mesmo banco de dados, mesmos dados, mesma aparência. Um deles é quatrocentas linhas mais curto.

Atualização

O componente faz parte do sgcHTML e é aditivo: nada muda em uma página existente até que você solte um no formulário.

Leia também

Assista ao vídeo

Há um vídeo curto sobre isso no canal da eSeGeCe.

Dúvidas, feedback ou ajuda com a migração? Entre em contato — você receberá uma resposta das pessoas que escreveram o código.