CRUD
TsgcHTMLComponent_CRUD: Liste, Suche, Paginierung, Formular zum Anlegen und Bearbeiten, Löschbestätigung und Schreibpfad einer Tabelle als eine einzige Komponente, über ein TDataSet oder Ihr eigenes SQL, in Delphi, C++ Builder und .NET.
TsgcHTMLComponent_CRUD: Liste, Suche, Paginierung, Formular zum Anlegen und Bearbeiten, Löschbestätigung und Schreibpfad einer Tabelle als eine einzige Komponente, über ein TDataSet oder Ihr eigenes SQL, in Delphi, C++ Builder und .NET.
Die Seite, die jede Geschäftsanwendung für jede Tabelle neu schreibt, als eine Komponente. Geben Sie ihr ein Schlüsselfeld und ein Routenpräfix, binden Sie dann ein TDataSet oder übergeben Sie ihr einen Adapter mit sechs Methoden für Ihr eigenes SQL. ShowList liefert das Markup zurück, und was die Seite zurücksendet, läuft über ProcessAction.
TsgcHTMLComponent_CRUD, mit TsgcHTMLCRUDAdapter und TsgcHTMLCRUDAdapter_DataSet in derselben Unit
Die Liste mit Suche und Seitennavigation, das Formular zum Anlegen und Bearbeiten und die Löschbestätigung
Delphi, C++ Builder, .NET
Setzen Sie KeyField und RoutePrefix, binden Sie ein aktives DataSet und rufen Sie ShowList(search, page) auf. Für Ihr eigenes SQL übergeben Sie der Komponente stattdessen mit SetAdapter einen Adapter. Leiten Sie alles, was die Seite zurücksendet, an ProcessAction weiter.
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
Die Member, die Sie am häufigsten verwenden.
TsgcHTMLCRUDAdapter ist der Schreibpfad, mit sechs virtuellen Methoden: Locate, Read, List, Insert, Update und Delete. TsgcHTMLCRUDAdapter_DataSet steuert das gebundene Dataset, und mit SetAdapter übergeben Sie der Komponente einen eigenen Adapter, dessen Besitz sie übernimmt. List liefert eine Seite als tabulatorgetrennte Zeilen, den Schlüssel als letzte Zelle, und gibt zurück, wie viele Zeilen die gesamte Menge hat.
Es gibt kein TDataSet, daher bringt die Portierung drei Adapter mit: TsgcHTMLCRUDAdapter_DataTable über eine DataTable, TsgcHTMLCRUDAdapter_List<T> über eine beliebige IList<T> und TsgcHTMLCRUDAdapter_DbConnection über eine Tabelle hinter einer DbConnection, wobei jeder Wert als Parameter gesendet wird. Deklarieren Sie die Columns selbst, denn sie werden nicht aus der Tabelle gelesen.
ShowList(search, page), ShowNew, ShowEdit(key), Save(key, values, html) und DeleteRecord(key, html) liefern jeweils das Markup, das der Host einsetzt. ProcessAction leitet die gesendeten crudList, crudNew, crudEdit, crudSave und crudDelete an sie weiter und antwortet mit False auf jede andere Aktion, damit eine Seite mehrere Komponenten enthalten kann.
Actions ist eine Menge aus caCreate, caEdit, caDelete, caView und caExport, und eine Seite mit nur caView ist ein Bericht. EditMode ist cemModal oder cemPage, ConfirmDelete fragt vor dem Löschen nach, PageSize ist standardmäßig 25 und geht nie über 500 hinaus, und SearchFields listet die Felder auf, in denen das Suchfeld sucht, durch Semikolons getrennt.
Eine TsgcHTMLCRUDColumn hat FieldName, Caption, Visible, ReadOnly, Required, InList, InForm, Width und MaxLength. Sind keine deklariert, liest die Komponente sie aus dem aktiven Dataset: die Beschriftung aus DisplayLabel, dazu das Pflichtfeld-Kennzeichen und die Länge, und der Schlüssel wird angezeigt, aber nie bearbeitet. LoadColumnsFromDataSet erledigt das auf Anforderung.
Eine leere Pflichtspalte und ein Wert, der länger als MaxLength ist, werden zuerst abgelehnt. Danach wird OnValidate befragt: Fügen Sie aErrors je Problem eine Zeile hinzu, dann wird nichts geschrieben, und das Formular kommt mit den Meldungen zurück. OnApplyUpdates läuft vor dem Adapter, und wenn Sie aHandled setzen, übernehmen Sie das Schreiben selbst. OnApplied wird ausgelöst, nachdem ein Schreibvorgang durchgelaufen ist, um ihn zu protokollieren oder alle zu aktualisieren, die gerade dieselbe Liste ansehen.
Tragen Sie in VersionField ein Versionsfeld ein. Beim Speichern wird verglichen, was der Browser sendet, mit dem, was gespeichert ist, und der Schreibvorgang wird abgelehnt, wenn inzwischen jemand anderes den Datensatz geändert hat. So überschreibt die Person, die als zweite auf Speichern klickt, nicht die Änderung der ersten.
Details enthält die untergeordneten Listen eines Datensatzes. Jedes Element nennt eine weitere TsgcHTMLComponent_CRUD in CRUD, in MasterField das Feld der Detailliste, das den Master-Schlüssel enthält, und eine Caption. Sie werden unter dem Formular dargestellt, solange ein Datensatz bearbeitet wird. SetMaster(field, value) schränkt eine Liste auf einen Master-Datensatz ein.
Mit caExport zeigt die Toolbar einen Export-Link auf RoutePath('export.csv'). Beantworten Sie diese Route mit GetExportCSV(search). Exportiert wird die Suche, die die Liste gerade anzeigt, bis zu 500 Zeilen, nicht die ganze Tabelle. Jeder Wert steht in Anführungszeichen, sodass ein Komma oder ein Zeilenumbruch die Datei nicht beschädigen kann.
Jeder Schlüssel kommt vom Browser. ShowEdit, Save und DeleteRecord lassen den Adapter ihn mit Locate suchen, bevor etwas bearbeitet oder gelöscht wird, sodass das Ändern einer Zahl in einer URL nie einen anderen Datensatz erreicht. Actions wird ebenfalls durchgesetzt: Eine Seite ohne caDelete lehnt einen Löschvorgang auch dann ab, wenn ein gefälschtes Formular einen sendet. Zellen und Felder werden maskiert, sodass ein Datensatz, der Markup enthält, als Text angezeigt wird.
Das Suchfeld, Neu, Bearbeiten, Löschen und das Formular sind Formulare, die mit data-sgc-ws-send markiert sind, jeweils mit den versteckten Feldern action, crud und key, und der Host übergibt sie an ProcessAction. Eine Nachricht über den Socket trägt keinen Pfad und erreicht den Router nie, daher müssen Sie sie selbst autorisieren. In Delphi liefert TsgcHTMX_Engine_Server.MessageSession die Sitzung hinter den Handshake-Cookies oder nil. Für HTTP baut RoutePath die Pfade, die ein Host am Engine-Router deklariert: /customers, /customers/new, /customers/{id}/edit, /customers/save und /customers/{id}/delete.
Erstellen Sie sie wie oben im Code oder nutzen Sie den Assistenten in der Delphi-IDE: Tools › New sgcHTML CRUD page listet die Datasets des geöffneten Formulars auf, liest die Felder des ausgewählten Datasets und fügt dem Formular eine konfigurierte Komponente hinzu, wobei die beiden Verdrahtungszeilen in der Zwischenablage liegen. Dafür ist Delphi 10.4 oder höher erforderlich. Außerhalb der IDE schreibt das Kommandozeilenwerkzeug sgcHTMLGen den Quelltext der Seite in Object Pascal oder in C# aus der Tabelle, dem Routenpräfix und den Feldern, die jeweils als name:flag angegeben werden, zum Beispiel ID:key oder NAME:req:60.
Teil von sgcHTML, das unabhängig von sgcWebSockets verkauft wird. Die Unit kompiliert überall dort, wo SGC_HTML definiert ist, was sgcVer.inc für das HTML-Paket auf jeder Plattform außer Android und iOS tut. Die Demo ist Demos\60.HTML\01.RunTime\02.AdminCRUD, in der der Kundenbereich auf dieser Komponente aufgebaut ist, neben der von Hand geschriebenen Seite, die sie ersetzt hat.
| Online-HilfeAnleitung zur Verwendung von CRUD-Seiten, des Adapters und des Schreibpfads. | Öffnen | |
| Alle sgcHTML-KomponentenDurchsuchen Sie die vollständige Funktionsmatrix von über 80 Komponenten. | Öffnen | |
| Kostenlose Testversion herunterladenDie 30-Tage-Testversion enthält die 60.HTML-Demoprojekte. | Öffnen | |
| PreiseSingle-, Team- und Site-Lizenzen mit vollständigem Quellcode. | Öffnen |