Tutorial: CRUD de Base de Datos

Este tutorial lo guia a traves de la construccion de una aplicacion de base de datos completa con operaciones de Crear, Leer, Actualizar y Eliminar usando SQLite. Conectara a una base de datos, mostrara registros en una cuadricula TBrowse y los navegara con TDBNavigator.

Paso 1: Crear el Proyecto

  1. Cree un nuevo proyecto llamado ContactsDB mediante Archivo → Nuevo Proyecto.
  2. Abra main.prg en el Editor de Codigo.
  3. Construiremos un gestor de contactos con campos de nombre, correo y telefono.

Paso 2: Conectar a SQLite

Coloque un componente TSQLite desde la pestania de paleta Acceso a Datos en el formulario, o creelo en codigo. El componente SQLite de HarbourBuilder maneja la conexion y ejecucion de consultas.

#include "hbbuilder.ch"

function Main()

   local oDB, oForm

   // Abrir (o crear) el archivo de base de datos SQLite
   DEFINE SQLITE oDB FILE "contacts.db"

   if .not. oDB:lConnected
      MsgAlert( "Error al abrir la base de datos: " + oDB:cError )
      return nil
   endif

   CreateTable( oDB )
   BuildUI( oDB )

return nil
SQLite no requiere servidor

SQLite almacena toda la base de datos en un unico archivo. Esto lo hace perfecto para aplicaciones de escritorio — sin instalacion, sin configuracion, y funciona en todas las plataformas.

Paso 3: Crear la Tabla

Use Execute() para ejecutar una sentencia CREATE TABLE IF NOT EXISTS. Es seguro llamar a esto cada vez que la aplicacion se inicia.

static function CreateTable( oDB )

   oDB:Execute( "CREATE TABLE IF NOT EXISTS contacts (" + ;
      "id INTEGER PRIMARY KEY AUTOINCREMENT," + ;
      "name TEXT NOT NULL," + ;
      "email TEXT," + ;
      "phone TEXT" + ;
      ")" )

return nil

Paso 4: Construir la Interfaz de Usuario

La UI consiste en una cuadricula TBrowse para mostrar registros, campos de entrada para edicion, un TDBNavigator para navegacion de registros y botones CRUD.

static function BuildUI( oDB )

   local oForm, oBrw, oNav
   local oGetName, oGetEmail, oGetPhone
   local oBtnAdd, oBtnUpdate, oBtnDelete
   local cName := "", cEmail := "", cPhone := ""

   DEFINE FORM oForm TITLE "Gestor de Contactos" ;
      SIZE 800, 600 FONT "Segoe UI", 10

   // --- Cuadricula de datos ---
   @ 10, 10 BROWSE oBrw ;
      OF oForm SIZE 760, 300 ;
      HEADERS { "ID", "Nombre", "Correo", "Telefono" } ;
      WIDTHS  { 50, 200, 250, 150 }

   // --- Barra de navegacion ---
   @ 320, 10 DBNAVIGATOR oNav ;
      OF oForm SIZE 300, 32 ;
      BROWSE oBrw

   // --- Campos de entrada ---
   @ 370, 10 LABEL oLbl1 VALUE "Nombre:"   OF oForm SIZE 60, 24
   @ 370, 80 GET oGetName VAR cName     OF oForm SIZE 250, 24

   @ 400, 10 LABEL oLbl2 VALUE "Correo:"  OF oForm SIZE 60, 24
   @ 400, 80 GET oGetEmail VAR cEmail   OF oForm SIZE 250, 24

   @ 430, 10 LABEL oLbl3 VALUE "Telefono:"  OF oForm SIZE 60, 24
   @ 430, 80 GET oGetPhone VAR cPhone   OF oForm SIZE 250, 24

   // --- Botones CRUD ---
   @ 480, 80 BUTTON oBtnAdd PROMPT "Anadir" ;
      OF oForm SIZE 90, 32 ;
      ACTION DoInsert( oDB, oBrw, oGetName, oGetEmail, oGetPhone )

   @ 480, 180 BUTTON oBtnUpdate PROMPT "Actualizar" ;
      OF oForm SIZE 90, 32 ;
      ACTION DoUpdate( oDB, oBrw, oGetName, oGetEmail, oGetPhone )

   @ 480, 280 BUTTON oBtnDelete PROMPT "Eliminar" ;
      OF oForm SIZE 90, 32 ;
      ACTION DoDelete( oDB, oBrw )

   // Cargar datos iniciales
   RefreshBrowse( oDB, oBrw )

   // Cuando el usuario hace clic en una fila, poblar los campos de entrada
   oBrw:OnClick := { || OnRowSelect( oBrw, oGetName, oGetEmail, oGetPhone ) }

   ACTIVATE FORM oForm CENTERED

return nil

Paso 5: Implementar Operaciones CRUD

INSERT — Anadir un Nuevo Registro

static function DoInsert( oDB, oBrw, oGetName, oGetEmail, oGetPhone )

   local cName  := oGetName:GetValue()
   local cEmail := oGetEmail:GetValue()
   local cPhone := oGetPhone:GetValue()

   if Empty( cName )
      MsgAlert( "El nombre es obligatorio." )
      return nil
   endif

   oDB:Execute( "INSERT INTO contacts (name, email, phone) VALUES (?, ?, ?)", ;
      { cName, cEmail, cPhone } )

   RefreshBrowse( oDB, oBrw )
   MsgInfo( "Contacto anadido." )

return nil

SELECT — Actualizar la Cuadricula

static function RefreshBrowse( oDB, oBrw )

   local aRows := oDB:QueryToArray( "SELECT id, name, email, phone FROM contacts ORDER BY name" )

   oBrw:SetArray( aRows )
   oBrw:Refresh()

return nil

UPDATE — Modificar el Registro Seleccionado

static function DoUpdate( oDB, oBrw, oGetName, oGetEmail, oGetPhone )

   local nId    := oBrw:GetValue( 1 )  // Columna 1 = id
   local cName  := oGetName:GetValue()
   local cEmail := oGetEmail:GetValue()
   local cPhone := oGetPhone:GetValue()

   if nId == 0
      MsgAlert( "Seleccione un contacto primero." )
      return nil
   endif

   oDB:Execute( "UPDATE contacts SET name=?, email=?, phone=? WHERE id=?", ;
      { cName, cEmail, cPhone, nId } )

   RefreshBrowse( oDB, oBrw )
   MsgInfo( "Contacto actualizado." )

return nil

DELETE — Eliminar el Registro Seleccionado

static function DoDelete( oDB, oBrw )

   local nId := oBrw:GetValue( 1 )

   if nId == 0
      MsgAlert( "Seleccione un contacto primero." )
      return nil
   endif

   if MsgYesNo( "Eliminar este contacto?" )
      oDB:Execute( "DELETE FROM contacts WHERE id=?", { nId } )
      RefreshBrowse( oDB, oBrw )
      MsgInfo( "Contacto eliminado." )
   endif

return nil

Seleccion de Fila — Poblar Campos de Entrada

static function OnRowSelect( oBrw, oGetName, oGetEmail, oGetPhone )

   oGetName:SetValue(  oBrw:GetValue( 2 ) )
   oGetEmail:SetValue( oBrw:GetValue( 3 ) )
   oGetPhone:SetValue( oBrw:GetValue( 4 ) )

return nil

Paso 6: Usar TDBNavigator

El control TDBNavigator proporciona botones de navegacion estandar (Primero, Anterior, Siguiente, Ultimo) que funcionan directamente con la cuadricula TBrowse. Coloquelo desde la pestania Acceso a Datos y establezca su propiedad oBrowse a su instancia TBrowse.

Las consultas parametrizadas previenen la inyeccion SQL

Siempre use marcadores ? y pase los valores como un arreglo. Nunca concatene entrada del usuario directamente en cadenas SQL. El componente SQLite de HarbourBuilder maneja el escape automaticamente.

Arquitectura de la Aplicacion

graph TD A["Capa UI
TForm + TBrowse + TGet"] --> B["Manejadores de Eventos
DoInsert / DoUpdate / DoDelete"] B --> C["Capa de Datos
Componente TSQLite"] C --> D["Archivo SQLite
contacts.db"] D --> C C --> B B --> E["RefreshBrowse
QueryToArray + SetArray"] E --> A style A fill:#58a6ff,stroke:#388bfd,color:#0d1117 style B fill:#d2a8ff,stroke:#bc8cff,color:#0d1117 style C fill:#3fb950,stroke:#2ea043,color:#0d1117 style D fill:#f0883e,stroke:#d18616,color:#0d1117
Siguiente paso

Listo para servir datos por HTTP? Continue al tutorial de Servidor Web para construir una aplicacion web junto a su aplicacion de escritorio.

En Esta Página

Primeros Pasos Paleta de Componentes Funciones del IDE Tutoriales Referencia Plataformas Paso 1: Crear el Proyecto Paso 2: Conectar a SQLite Paso 3: Crear la Tabla Paso 4: Construir la Interfaz de Usuario Paso 5: Implementar Operaciones CRUD INSERT — Anadir un Nuevo Registro SELECT — Actualizar la Cuadricula UPDATE — Modificar el Registro Seleccionado DELETE — Eliminar el Registro Seleccionado Seleccion de Fila — Poblar Campos de Entrada Paso 6: Usar TDBNavigator Arquitectura de la Aplicacion