CRUD

TsgcHTMLComponent_CRUD: el listado, la búsqueda, la paginación, el formulario de alta y edición, la confirmación de eliminación y la ruta de escritura de una tabla como un único componente, sobre un TDataSet o tu propio SQL, en Delphi, C++ Builder y .NET.

TsgcHTMLComponent_CRUD

La página que toda aplicación de negocio reescribe para cada tabla, como un único componente. Indícale un campo clave y un prefijo de ruta, y luego enlaza un TDataSet o pásale un adaptador de seis métodos sobre tu propio SQL. ShowList responde con el marcado, y lo que la página envía de vuelta pasa por ProcessAction.

Clase del componente

TsgcHTMLComponent_CRUD, con TsgcHTMLCRUDAdapter y TsgcHTMLCRUDAdapter_DataSet en la misma unidad

Genera

El listado con búsqueda y paginador, el formulario de alta y edición, y la confirmación de eliminación

Familia

Datos y Tablas

Lenguajes

Delphi, C++ Builder, .NET

Enlaza un dataset, o escribe el adaptador

Define KeyField y RoutePrefix, enlaza un DataSet activo y llama a ShowList(search, page). Para tu propio SQL, dale en su lugar al componente un adaptador con SetAdapter. Enruta lo que la página envía de vuelta a través de 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

Propiedades y métodos clave

Los miembros que usarás con más frecuencia.

Adaptador

TsgcHTMLCRUDAdapter es la ruta de escritura, con seis métodos virtuales: Locate, Read, List, Insert, Update y Delete. TsgcHTMLCRUDAdapter_DataSet maneja el dataset enlazado, y SetAdapter le da al componente uno propio, del que pasa a ser propietario. List devuelve una página como líneas separadas por tabuladores, con la clave como última celda, e indica cuántas filas tiene el conjunto completo.

En .NET

No hay TDataSet, así que la versión .NET incluye tres adaptadores: TsgcHTMLCRUDAdapter_DataTable sobre un DataTable, TsgcHTMLCRUDAdapter_List<T> sobre cualquier IList<T> y TsgcHTMLCRUDAdapter_DbConnection sobre una tabla tras un DbConnection, con cada valor enviado como parámetro. Declara las Columns: no se leen de la tabla.

La página

ShowList(search, page), ShowNew, ShowEdit(key), Save(key, values, html) y DeleteRecord(key, html) devuelven cada uno el marcado que el host intercambia en la página. ProcessAction enruta hacia ellos los envíos crudList, crudNew, crudEdit, crudSave y crudDelete, y responde False para cualquier otra acción, de modo que una página pueda contener varios componentes.

Opciones de la página

Actions es un conjunto de caCreate, caEdit, caDelete, caView y caExport, y una página con solo caView es un informe. EditMode es cemModal o cemPage, ConfirmDelete pregunta antes de eliminar, PageSize vale 25 por defecto y nunca supera 500, y SearchFields lista los campos en los que busca el cuadro de búsqueda, separados por punto y coma.

Columns

Un TsgcHTMLCRUDColumn tiene FieldName, Caption, Visible, ReadOnly, Required, InList, InForm, Width y MaxLength. Si no se declara ninguna, el componente las lee del dataset activo: el título de DisplayLabel, el indicador de obligatorio y la longitud, y la clave se muestra pero nunca se edita. LoadColumnsFromDataSet lo hace a petición.

Validación

Primero se rechazan una columna obligatoria vacía y un valor más largo que MaxLength. Después se consulta a OnValidate: añade una línea por problema a aErrors y no se escribe nada, el formulario vuelve con los mensajes. OnApplyUpdates se ejecuta antes que el adaptador, y si asignas aHandled la escritura pasa a ser tuya. OnApplied se dispara cuando una escritura se ha realizado, para registrarla o refrescar a quien más esté viendo el listado.

Bloqueo optimista

Indica un campo de versión en VersionField. Un guardado compara lo que envía el navegador con lo almacenado, y rechaza la escritura cuando otra persona ha cambiado el registro entretanto, de modo que la segunda persona que pulse Guardar no sobrescribe a la primera.

Maestro y detalle

Details contiene las listas hijas de un registro. Cada elemento nombra otro TsgcHTMLComponent_CRUD en CRUD, el campo del hijo que contiene la clave del maestro en MasterField, y un Caption. Se muestran bajo el formulario mientras se edita un registro. SetMaster(field, value) acota una lista a un registro maestro.

Exportación a CSV

Con caExport la barra de herramientas muestra un enlace Exportar a RoutePath('export.csv'). Responde a esa ruta con GetExportCSV(search): exporta la búsqueda que muestra el listado, hasta 500 filas, no toda la tabla. Todos los valores van entre comillas, de modo que una coma o un salto de línea no pueden romper el archivo.

La clave se localiza primero

Todas las claves llegan desde el navegador. ShowEdit, Save y DeleteRecord piden al adaptador que la localice con Locate antes de editar o eliminar nada, de modo que cambiar un número en una URL nunca llega a otro registro. Actions también se aplica: una página sin caDelete rechaza una eliminación aunque un formulario falsificado envíe una. Las celdas y los campos se escapan, así que un registro que contiene marcado se muestra como texto.

Socket y HTTP

El cuadro de búsqueda, Nuevo, Editar, Eliminar y el formulario son formularios marcados con data-sgc-ws-send, cada uno con campos ocultos action, crud y key, y el host los entrega a ProcessAction. Un mensaje por el socket no lleva ruta y nunca llega al enrutador, así que autorízalo tú mismo. En Delphi, TsgcHTMX_Engine_Server.MessageSession devuelve la sesión que hay tras las cookies del handshake, o nil. Para HTTP, RoutePath construye las rutas que un host declara en el enrutador del motor: /customers, /customers/new, /customers/{id}/edit, /customers/save y /customers/{id}/delete.

Formas de empezar

Créalo en código, como arriba, o usa el asistente del IDE de Delphi: Tools › New sgcHTML CRUD page lista los datasets del formulario abierto, lee los campos del que elijas y añade al formulario un componente configurado, con las dos líneas de conexión en el portapapeles. Requiere Delphi 10.4 o posterior. Fuera del IDE, la herramienta de línea de comandos sgcHTMLGen escribe el código fuente de la página en Object Pascal o en C#, a partir de la tabla, el prefijo de ruta y los campos, cada uno escrito como name:flag, por ejemplo ID:key o NAME:req:60.

Disponibilidad

Forma parte de sgcHTML, que se vende de forma independiente de sgcWebSockets. La unidad se compila donde está definido SGC_HTML, algo que sgcVer.inc hace para el pack HTML en todas las plataformas excepto Android e iOS. La demo es Demos\60.HTML\01.RunTime\02.AdminCRUD, donde el área de clientes está construida sobre este componente junto a la página escrita a mano a la que sustituyó.

Sigue explorando

Ayuda en líneaGuía de uso de las páginas CRUD, el adaptador y la ruta de escritura.
Todos los componentes de sgcHTMLExplora la matriz completa de más de 80 componentes.
Descargar prueba gratuitaLa prueba de 30 días incluye los proyectos de demostración 60.HTML.
PreciosLicencias Single, Team y Site con código fuente completo.
La mejor opción: All-AccessTodos los productos de eSeGeCe, con Premium Support incluido, desde €1,059 al año.
Ver precios de All-Access

¿Listo para empezar?

Descarga la prueba gratuita y empieza a crear interfaces web en Delphi, C++ Builder y .NET.