Difference between revisions of "Lazarus Tdbf Tutorial/es"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting)
 
(91 intermediate revisions by 9 users not shown)
Line 1: Line 1:
 
{{Lazarus Tdbf Tutorial}}
 
{{Lazarus Tdbf Tutorial}}
 +
[[category:Castellano|D]][[category:Español|D]]
  
'''(Traduciendo.../On Translation...)'''
 
  
=Resumen=
+
== Resumen ==
  
Este tutorial trata sobre el desarrollo elemental de bases de datos usando el componente TDbf (de Micha Nelissen) con Lazarus. Hay disponible documentación adicional para TDbf. Esta página fue creada por [[User:Tonymaro | Tony Maro]], pero ¡se agradecen otras colaboraciones!
+
   Esta tutoría trata sobre el desarrollo elemental de bases de datos usando el componente [http://tdbf.sf.net TDbf] (de Micha Nelissen) con Lazarus. Hay disponible documentación adicional para TDbf. Esta página fue creada por [[User:Tonymaro | Tony Maro]], pero ¡se agradecen otras colaboraciones!
  
===Lo que necesitará===
+
   En Lazarus, el componente DbfLaz utiliza el código de FPC TDbf.
Sin duda pronto será más fácil cuando FreePascal libere la próxima versión 2.0, sin embargo, actualmente necesitará una versión reciente de CVS de FPC 1.9.X para usar adecuadamente el componente TDbf. Se puede descargar solo el componente TDbf y usarlo con la versión 1.1 de FreePascal, sin embargo, este documento fue escrito pensando en la 1.9.X, en parte debido a correcciones en otros componentes de bases de datos usados en Lazarus.
 
  
También necesitará instalar el paquete DbfLaz que trae Lazarus. Está situado en la carpeta lazarus/components/tdbf/.  
+
 
 +
 
 +
=== Documentación ===
 +
 
 +
   Para documentación de TDbf en PDF ir a [https://sourceforge.net/project/showfiles.php?group_id=34085&package_id=26371  SourceForge]. Puede ser útil tener este pdf junto con este documento durante su lectura.
 +
 
 +
Este artículo sirve como documentación adicional para nuevas características respecto a la documentación original.
 +
 
 +
=== Alternativas y problemas conocidos ===
 +
 
 +
   Alternativas para bases de datos embedias tales como Firebird embebido (ventaja: fácilmente escalable para cliente / servidor), SQLite (ventaja: fácil implementación), o ZMSQL (usa archivos CSV; ventaja: sólo necesita código Pascal).
 +
 +
   Problemas conocidos: El código TDbf careció de mantenedor por largo tiempo. Actualmente (marzo de 2013), tanto el proyecto ''upstream'' de Sourceforge (centrado en Delphi) como los desarrolladores de bases de datos FPC están de nuevo para arreglar errores de TDbf. Los errores corregidos en el trunk de FPC necesitarán fusionarse con la versión de SourceForge y viceversa.
 +
 
 +
Incidencias actuales: por favor ver bugs en el seguimiento de errores, especialmente http://bugs.freepascal.org/view.php?id=22177
 +
 
 +
==== Limitaciones ====
 +
 
 +
* TDBF establece la codificación de la base de datos basándose en las configuraciones del lenguaje del sistema operativo (puedes establecer el tuyo estableciendo LanguageID; ver documentación). Mover una de estas bases de datos a un computador que no soporta dicha codificación puede ocasionar que la base de datos se quede como de solo lectura. ''Nota: investigar cuando esto se aplica a Tablelevel 7 (Visual DBase) y 25/30 (Foxpro/Visual Foxpro)''
 +
 
 +
* Ninguno de los formatos DBF utilizados soporta codicación Unicode (si UTF-8, UTF-16 o UTF-32). Podría haber una solución utilizando campos binarios, pero entonces perderiamos habilidades de reordenación, etc.
 +
 
 +
* El indexado de un fichero DBase con [ixCaseInsensitive] no funciona actualmente.
 +
* No soporta todavía integridad referencial en formatos de fichero que si lo soportan (DBase VII, Visual FoxPro).
 +
* No soporta (ahora o bien para siempre) encriptación interna de ficheros .dbf: el mecanismo de encriptación de DbaseIV es bastante debil de todos modos. Por favor utiliza uno de los métodos de encriptación que se mencionan más abajo.
 +
 
 +
FPC 2.6.x y anteriores:
 +
* En procesadores ARM, el códigoTDBF es sabido que no funciona debido a incidencias de alineación de bus. Esto está siendo addressed en la versión de desarrollo/trunk.
 +
* Escoger el tablelevel (25) de FoxPro generará ficheros que no se podrán leer mediante drivers Visual Foxpro. Esto se ha solucionado en la versión de desarrollo/trunk de FPC.
 +
 
 +
=== No necesita instalación ===
 +
 
 +
  El paquete DbfLaz (dbflaz.lpk) viene instalado por defecto tanto en FPC como en Lazarus. Este paquete utiliza TDbf y sus unidades asociadas en Free Pascal Free Component Library. En otras palabras, no es necesario instalar nada si tienes justamente una versión reciente de Lazarus. Está situado en la carpeta lazarus/components/tdbf/.
  
 
===¿Qué se puede hacer con TDbf?===
 
===¿Qué se puede hacer con TDbf?===
El componente TDbf proporciona a Lazarus (y otros entornos) acceso a tablas dBase y FoxPro. Permite la lectura, la escritura y la creación de tablas dBase III+, dBase IV, dBase visual VII y FoxPro. Hace todo esto sin la necesidad de bibliotecas o de gestores de bases de datos adicionales. Simplemente ponga el componente TDbf en su formulario y tendrá acceso inmediato a un entorno de bases de datos de plataforma-cruzada. TDbf funciona tanto en Windows como en Linux usando Lazarus.
+
   El componente TDbf proporciona a Lazarus (y otros entornos) acceso a tablas dBase y FoxPro. Permite la lectura, escritura y creación de tablas dBase III+, dBase IV, Visual dBase VII y FoxPro. Y sin necesitar librerías o gestores de bases de datos adicionales. Simplemente ponga el componente TDbf en su formulario y tendrá acceso inmediato a un entorno de bases de datos de para múltiples plataformas. TDbf funciona tanto en Windows como en Linux usando Lazarus.
 +
 
 +
==Cómo crear una nueva tabla==
 +
 
 +
   Como no hay todavía una aplicación "Database Desktop" para Lazarus, debemos crear las tablas de la base de datos mediante código, o utilizando herramientas externas.
  
=Cómo crear una nueva tabla=
+
Puedes probar esta aplicación (windows - funciona con '''''wine'''''): http://www.dirfile.com/cdbf_explorer.htm
  
Como no hay todavía una aplicación "Database Desktop" para Lazarus, debemos crear una nueva base de datos mediante código.
+
===Establecer la ruta de acceso===
 +
   Es recomendable crear una carpeta para sus aplicaciones de bases de datos. Esto simplifica la realización de copias de seguridad de los datos. Hay dos maneras de establecer la ruta de acceso. Puede fijar la ruta completa usando la propiedad FilePathFull, o puede establecer una ruta relativa a la ruta del programa con FilePath. Por ejemplo, estableciendo "FilePath" en tiempo de ejecución a "datos/" utilizaría una subcarpeta de datos dentro de la carpeta del archivo ejecutable. Fijar la propiedad "FilePathFull"  a "/var/datos/" colocaría todo en esa carpeta, no teniendo en cuenta la ubicación del programa.
  
===Establecer la ruta===
+
=== Elegir un tipo de tabla con ''TableLevel''===
Es una buena idea dar a sus aplicaciones de bases de datos su propia carpeta. Esto simplifica la realización de copias de seguridad de los datos. Hay dos maneras de establecer la ruta. Puede fijar la ruta completa usando la propiedad FilePathFull, o puede establecer una ruta relativa a la ruta de la aplicación en uso con FilePath. Por ejemplo, estableciendo "FilePath" en tiempo de ejecución a "data/" utilizaría una subcarpeta de datos dentro de la carpeta del archivo ejecutable. Fijar la propiedad "FilePathFull"  a "/var/data/" colocaría todo en esa carpeta, no teniendo en cuenta la ubicación de la aplicación.
+
   Por omisión, TDbf creará tablas dBase IV. Aunque son muy compatibles, hay características que puede desear usar que no están disponibles. Para poder utilizar campos ''autoincrementales'', debe usar algo más nuevo. Los tipos de tabla posibles son:
  
===     Eligir un TableLevel===
+
<center><table style="text-align: center; " border="1">
Por omisión, TDbf creará tablas dBase IV. Aunque son muy compatibles, hay características que puede desear usar que no están disponibles. Para poder utilizar campos auto-incrementables, debe usar algo más nuevo. Los tipos de tabla posibles son:
+
     <tr>      <td>Tipos de tabla</td><td>TableLevel</td></tr>
 +
    <tr>      <td>dBase III+</td><td>3</td></tr>
 +
    <tr>      <td>dBase IV</td><td>4</td></tr>
 +
    <tr>      <td>Visual dBase VII</td><td>7</td></tr>
 +
    <tr>      <td>FoxPro</td><td>25</td></tr>
 +
</table></center>
  
*3 dBase III+
 
*4 dBase IV
 
*7 Visual dBase VII
 
*25 FoxPro
 
  
Para elegir un tipo de tabla seleccione apropiadamente la propiedad TableLevel.
+
&nbsp;&nbsp;&nbsp;Para elegir un tipo de tabla de el valor adecuado a la propiedad TableLevel.
  
 
=== Añadir campos===
 
=== Añadir campos===
Creating fields for your new table at runtime pretty much follows the old Delphi standard. Once you have set your FilePath, TableLevel, and TableName properties, manipulate the FieldDefs property to set up the structure. For example:
+
&nbsp;&nbsp;&nbsp;La creación de campos para su nueva tabla en tiempo de ejecución se realiza como en Delphi. Una vez establecidas las propiedades FilePath, TableLevel, y TableName, hay que utilizar la propiedad FieldDefs para determinar su estructura. Por ejemplo:
 
+
<syntaxhighlight lang=pascal> MyDbf.FilePathFull := '/ubicacion/para/mis/datos';
MyDbf.FilePathFull := '/location/to/my/data';
 
 
  MyDbf.TableLevel := 7;
 
  MyDbf.TableLevel := 7;
  MyDbf.TableName := 'customers.dbf'; // note: is the .dbf really required?
+
  MyDbf.TableName := 'clientes.dbf'; // nota: ¿es realmente necesario .dbf?
 
  With MyDbf.FieldDefs do begin
 
  With MyDbf.FieldDefs do begin
 
   Add('Id', ftAutoInc, 0, True);
 
   Add('Id', ftAutoInc, 0, True);
   Add('Name', ftString, 80, True);
+
   Add('Nombre', ftString, 80, True);
  End;
+
  End;</syntaxhighlight>
  
Field types are defined as:
+
&nbsp;&nbsp;&nbsp;Los tipos de campo definidos son:
  
 
*    ftUnknown
 
*    ftUnknown
Line 84: Line 120:
 
*    ftFMTBcd
 
*    ftFMTBcd
  
Bold types are currently supported
+
&nbsp;&nbsp;&nbsp;Los tipos que aparecen en negrita son los soportados en la actualidad.
===¡Continuar y crearla!===
 
Once you have defined the fields you wish to use in your new table, you can go ahead and create it with:
 
 
 
    MyDbf.CreateTable;
 
  
=Como añadir índices a una tabla=
+
===¡Siga adelante y créela!===
 +
&nbsp;&nbsp;&nbsp;Una vez que ha definido los campos deseará usarlos en su nueva tabla, puede seguir adelante y crearla con:
 +
<syntaxhighlight lang=pascal> MyDbf.CreateTable;</syntaxhighlight>
  
If your database is larger than a few records, chances are you will want to have indexes defined to make searching faster. To change the index structure of a table, we will want to have exclusive access to the table - which we would have while creating it anyway.
+
==Añadir índices a una tabla==
  
        MyDbf.Exclusive := True;
+
&nbsp;&nbsp;&nbsp;Si su base de datos es bastante grande, deberá definir índices para hacer búsquedas más rápidas. Para cambiar la estructura de índices de una tabla, deberemos tener acceso exclusivo a la tabla -mientras los creamos.  
        MyDbf.Open;
 
  
Now, we just have to add the index.
+
<syntaxhighlight lang=pascal> MyDbf.Exclusive := True;
 +
MyDbf.Open;</syntaxhighlight>
  
        MyDbf.AddIndex('custid', 'Id', [ixPrimary, ixUnique]);
+
&nbsp;&nbsp;&nbsp;Justo ahora, tenemos que añadir el índice.
        MyDbf.AddIndex('custname','Name', [ixCaseInsensitive]);
 
        MyDbf.Close;
 
  
= Póngalo todo junto y tendrá...=
+
<syntaxhighlight lang=pascal> MyDbf.AddIndex('clienteid', 'Id', [ixPrimary, ixUnique]);
 +
MyDbf.AddIndex('nombrecliente','Nombre', [ixCaseInsensitive]);
 +
MyDbf.Close;</syntaxhighlight>
  
The following sample creates a new table "customers" in code. This of course only needs done once, and after that you just OPEN the table, don't create it ;-)
+
==Lo unimos todo y ... ¡ya está!==
  
{ We will require the following units be in the USES clause: }
+
&nbsp;&nbsp;&nbsp;El siguiente ejemplo crea una tabla "clientes" mediante código. Esto, por supuesto, sólo es necesario hacerlo una vez para cada tabla, y de ahí en adelante, '''abrir la tabla, no crearla ;-)'''
  { uses Dbf, db, Dbf_Common                                   }
+
 
  { The Dbf is put there when you drop the TDbf on a form...  }
+
<syntaxhighlight lang=pascal> {Necesitamos que las siguientes unidades aparezcan en la clásula USES:}
  { but you will need db for the DataSet object and Dbf_Common }
+
  uses {otras unidades, } Dbf, db, Dbf_Common;
  { for things such as the field type definitions              }
+
  { "Dbf" aparecerá, automáticamente, cuando pongamos el componente TDbf en el formulario...  }
 +
  { pero necesitamos la unidad "db" para el objeto DataSet
 +
  { y la unidad "Dbf_Common" para las definiciones de tipos de campo, por ejemplo        }
 
  var
 
  var
 
   MyDbf: TDbf;
 
   MyDbf: TDbf;
Line 117: Line 153:
 
   MyDbf := TDbf.Create(nil);
 
   MyDbf := TDbf.Create(nil);
 
   try
 
   try
     { use relative path to "data" directory }
+
      
     MyDbf.FilePath := 'data/';  
+
     MyDbf.FilePath := 'datos/';   // usamos una ruta de acceso relativa para la carpeta "datos"
    { we want to use Visual dBase VII compatible tables }
+
     MyDbf.TableLevel := 7;         // utilizaremos tablas de tipo "Visual dBase VII"
     MyDbf.TableLevel := 7;
+
     MyDbf.Exclusive := True;       // imprescindible para poder modificar la estructura añadiendo campos
     MyDbf.Exclusive := True;
+
     MyDbf.TableName := 'clientes.dbf';
     MyDbf.TableName := 'customers.dbf';
 
 
     With MyDbf.FieldDefs do begin
 
     With MyDbf.FieldDefs do begin
 
       Add('Id', ftAutoInc, 0, True);
 
       Add('Id', ftAutoInc, 0, True);
       Add('Name', ftString, 80, True);
+
       Add('Nombre', ftString, 80, True);
 
     End;
 
     End;
 
     MyDbf.CreateTable;
 
     MyDbf.CreateTable;
 
     MyDbf.Open;
 
     MyDbf.Open;
     MyDbf.AddIndex('custid', 'Id', [ixPrimary, ixUnique]);
+
     MyDbf.AddIndex('clienteid', 'Id', [ixPrimary, ixUnique]);
     { add a secondary index }
+
     { añadimos un índice secundario }
     MyDbf.AddIndex('custname','Name', [ixCaseInsensitive]);
+
     MyDbf.AddIndex('nombrecliente','Nombre', [ixCaseInsensitive]);
 
     MyDbf.Close;
 
     MyDbf.Close;
 
   finally
 
   finally
 
     MyDbf.Free;
 
     MyDbf.Free;
   end;
+
   end;</syntaxhighlight>
  end;
+
 
 +
==Archivos índice externos==
 +
 
 +
&nbsp;&nbsp;&nbsp;El componente TDBF también soporta índices secundarios que se almacenan en un archivo separado. Esto será útil cuándo la base de datos sea muy grande, al poder separar en varios archivos los distintos índices. Los archivos de índice secundarios se crean de forma muy parecida a los índices normales, pero con la adición de la extensión '.ndx ' en el nombre:
 +
 
 +
<syntaxhighlight lang=pascal> MyDbf.AddIndex('nombrecliente.ndx','Nombre', [ixCaseInsensitive]);</syntaxhighlight>
 +
&nbsp;&nbsp;&nbsp;Estos índices no se gestionan de forma automática, por ello cada vez que se abre la tabla, se deberán cargar los archivos de índice que deseamos utilizar, usando el método ''OpenIndexFile'', así:
 +
<syntaxhighlight lang=pascal> MyDbf.OpenIndexFile('nombrecliente.ndx');</syntaxhighlight>
 +
&nbsp;&nbsp;&nbsp;Por la misma razón los índices se empaquetan por separado, para ello utilizaremos el método ''CompactIndexFile'', de esta forma:
 +
<syntaxhighlight lang=pascal> MyDbf.CompactIndexFile('nombrecliente.ndx');</syntaxhighlight>
 +
&nbsp;&nbsp;&nbsp;Y al dar el valor a la propiedad ''IndexName'', para seleccionar el que estará activo, debemos incluir el nombre y la extensión:
 +
<syntaxhighlight lang=pascal> MyDbf.IndexName := 'nombrecliente.ndx';</syntaxhighlight>
 +
 
 +
==Cómo enlazar TDbf a componentes de datos==
 +
 
 +
&nbsp;&nbsp;&nbsp;Los ejemplos anteriores muestran como crear una nueva tabla de base de datos mediante código. Usar la tabla es aún más simple.
 +
 
 +
&nbsp;&nbsp;&nbsp;Los  componentes de acceso a datos en Lazarus (como ''TDBEdit'' y ''TDbNavigator'' por ejemplo) se vinculan a un componente ''TDataSource'' mediante las propiedades ''DataSource'' y  ''DataField''. El componente ''TDataSource'' controla la comunicación entre el gestor de bases de datos y los componentes de acceso a datos. Un ''TDataSource'' se vincula al componente ''TDbf'' mediante su propiedad ''DataSet''. La conexión sería así:
  
= Archivos índice externos=
+
<code> TDbEdit------\
 +
              |
 +
  TDbEdit------|-->TDataSource-->TDbf
 +
              |
 +
  TDbNavigator-/</code>
  
The TDbf also supports storing secondary indexes in a separate file. This might be helpful if the database is expected to be very large. Secondary index files are created almost identically to normal indexes, but with the addition of the '.ndx' file extension:
+
&nbsp;&nbsp;&nbsp;No olvides establecer las propiedades ''FilePath'' (o ''FilePathFulll''), ''TableLevel'', y ''TableName'' del componente ''TDbf'' a los valores adecuados antes de activarlos mediante
  
    MyDbf.AddIndex('custname.ndx','Name', [ixCaseInsensitive]);
+
<syntaxhighlight lang=pascal> TDbf.Active := True;</syntaxhighlight>
  
 +
&nbsp;&nbsp;&nbsp;Se podría decir mucho más sobre programación con bases de datos en Lazarus, y yo recomendaría un buen libro de programación de bases de datos con Delphi porque los conceptos fundamentales son los mismos. Constantemente hago referencia a mi ejemplar de "Liberado Delphi 2" porque los conceptos y el código básico no han cambiado mucho en 8 años.
  
Each time the TDbf is opened, the index file must be loaded:
+
==Empaquetar y reconstruir índices==
  
    MyDbf.OpenIndexFile('custname.ndx');
+
&nbsp;&nbsp;&nbsp;Cuando se borra un registro, realmente no desaparece físicamente del archivo que guarda la tabla. De vez en cuando debe ''empaquetar'' la tabla para eliminar realmente los registros y así recuperar ese espacio desaprovechado del archivo. Esto hay que hacerlo teniendo la tabla abierta en modo exclusivo.
  
 +
<syntaxhighlight lang=pascal> MyDbf.Exclusive := True;
 +
MyDbf.Open;
 +
MyDbf.PackTable;
 +
// reconstruimos todos los índices
 +
MyDbf.RegenerateIndexes;
 +
MyDbf.Close;
 +
MyDbf.Exclusive := False;</syntaxhighlight>
  
And indexes must be referenced including the extension:
+
==Relaciones de tabla principal==
  
    MyDbf.IndexName := 'custname.ndx';
+
&nbsp;&nbsp;&nbsp;La verdadera potencia de la programación de bases de datos comienza cuando tenemos múltiples tablas que se hacen referencia mutuamente. Mientras que TDbf aún no soporta la integridad referencial, si soporta una relación del tipo maestro/detalle entre componentes TDbf.
  
 +
&nbsp;&nbsp;&nbsp;Cuando hay dos tablas relacionadas, por ejemplo:
  
Index files are packed separately using:
+
  ['''clientes''']
 +
  Id      <----\
 +
  Nombre        |
 +
  Telefono      |
 +
  Direccion    |
 +
                |  ClienteID en facturas hace referencia a un campo primario de clientes
 +
  ['''facturas''']    |
 +
  Id            |
 +
  Importe      |
 +
  ClienteID  --\---|  * Campo indexado como "idxclienteid"
  
    MyDbf.CompactIndexFile('custname.ndx');
+
&nbsp;&nbsp;&nbsp;Si desea mostrar todas las facturas para un cliente determinado, la tabla detalle (facturas) puede sincronizarse con la tabla principal (clientes) automáticamente.
  
= Cómo enlazar TDbf a componentes de datos=
+
&nbsp;&nbsp;&nbsp;En el componente TDbf de facturas seleccione lo siguiente:
  
The above examples show how to create a new database table in code. Using that table is even more simple.
+
<syntaxhighlight lang=pascal> InvDbf.IndexName := 'idxclienteid'; // campo que se emparejará con el campo ID de la tabla clientes                                   
 +
InvDbf.MasterSource := dsClientes;  // fuente de datos que se enlaza al componente TDbf de clientes
 +
InvDbf.MasterFields := 'Id';        // campo en la tabla clientes que emparejamos con nuestro índice</syntaxhighlight>
  
Data aware components in Lazarus (such as the TDbEdit control) link to a TDataSource component using their "DataSource" and "DataField" properties. The TDataSource component handles communication between the database engine and the data aware components. A TDataSource then links to the TDbf component using it's "DataSet" property. The connection looks like this:
+
== Cómo filtrar las Fechas vacías ==
  
TDbEdit-------
+
&nbsp;&nbsp;&nbsp;Voy a mostrar aquí como podemos filtrar las fechas en blanco con el componente de Lazarus TDbf.
              |
 
TDbEdit------|-->TDataSource-->TDbf
 
              |
 
TDbNavigator--
 
  
 +
&nbsp;&nbsp;&nbsp;Considérese que en este ejemplo, el componente se denomina datos dbf1 y la base de datos tiene un campo, DT_ENCERRA, que indica cuando el caso  se completó. Imagina también que necesitas crear un informe utilizando LazReport que enumera todos los casos que siguen pendientes, con el campo DT_ENCERRA en blanco.
  
Be sure to set the FilePath (or FilePathFulll), TableLevel, and TableName properties of your TDbf component before calling
+
&nbsp;&nbsp;&nbsp;La forma más sencilla de hacerlo es utilizando el controlador de eventos OnFilterRecord y poner el siguiente código:
  
TDbf.Active := True;
+
<syntaxhighlight lang=pascal> if not dfb1.FieldByName('DT_ENCERRA').IsNull then Accept := False;</syntaxhighlight>
  
 +
&nbsp;&nbsp;&nbsp;Cuando ponemos el valor de Accept a False todos los registros que no cumplen con esa condición particular, no se tienen en cuenta, es decir, no se muestran en el informe.
  
There is much more that can be said about programming with databases in Lazarus, and I would recommend a good Delphi database programming book or two as the underlying concepts are the same. I constantly refer to my copy of "Delphi 2 Unleashed" because the concepts and basic code haven't changed much in 8 years.
+
&nbsp;&nbsp;&nbsp;También es necesario poner la propiedad Dbf1.Filtered a True, pero fuera de este evento.
  
= Empaquetar y reconstruir índices=
+
<syntaxhighlight lang=pascal> dfb1.Filtered := True;</syntaxhighlight>
  
When a record is deleted, it's not truly removed from the physical table. Periodically you must "pack" a table to recover that lost space. This should be done with exclusive mode set.
+
== Cómo filtrar un valor con TDbf ==
  
MyDbf.Exclusive := True;
+
&nbsp;&nbsp;&nbsp;Supón que tienes una base de datos que identifica los productos con un código, por ejemplo, B019, y es necesario filtrar sólo aquellos productos que son de este código (B019, en este ejemplo) de manera que se genera un informe con LazReport. El componente se llama Dbf1. El campo que almacena el valor es "product_no"
MyDbf.Open;
 
MyDbf.PackTable;
 
// let's also rebuild all the indexes
 
MyDbf.RegenerateIndexes;
 
MyDbf.Close;
 
MyDbf.Exclusive := False;
 
  
= Relaciones de tabla principal=
+
&nbsp;&nbsp;&nbsp;Tenemos dos maneras de filtrar. La primera sería la de utilizar el siguiente código:
  
Real power in database programming begins when you have multiple tables that reference each other. While TDbf does not yet support referential integrity, it does support a master / detail relationship between TDbf's.
+
<syntaxhighlight lang=pascal> Dbf1.filter:= 'product_no "=" B019 "';</syntaxhighlight>
  
When there are two tables related, for instance:
+
&nbsp;&nbsp;&nbsp;Resulta que esto funciona muy bien con varios componentes, pero no funciona con LazReport.
  
[customers]
+
&nbsp;&nbsp;&nbsp;Para resolver el problema con LazReport puede utilizar el controlador de eventos OnFilterRecord y utilizar el siguiente código:
Id      <----|
 
Name          |
 
Phone        |
 
Address      |
 
              |  The CustID in invoices references a customer primary  field
 
[invoices]    |
 
Id            |
 
Amount        |
 
CustID  -----|  * This field indexed as "idxcustid"
 
  
 +
<syntaxhighlight lang=pascal> Accept:= Copy(Trim(Dbf1.FieldByName('product_no').AsString),1,4)='B019';</syntaxhighlight>
  
If you wanted to display all invoices for a given customer, the detail table (invoices) can stay in sync with the master table (customers) automatically.
+
&nbsp;&nbsp;&nbsp;También es necesario poner la propiedad Dbf1.Filtered a True, pero fuera de este evento.
  
On the invoices TDbf component set the following:
+
&nbsp;&nbsp;&nbsp;Como se dijo antes, cuando el valor de Accept es false los registros no se tienen en cuenta y de esta manera puede evitar mostrar todos los productos con ese código en el informe LazReport
  
InvDbf.IndexName := 'idxcustid'; // our field that will match the customers table ID
+
==Programa de ejemplo - navegador DB==
InvDbf.MasterSource := dsCustomers; // datasource that is linked to the customers TDbf
+
&nbsp;&nbsp;&nbsp;He escrito un programa sencillo que utiliza el componente TDbf para abrir y mostrar tablas de bases de datos mediante el control dbGrid. El ejecutable Linux, junto con las fuentes del proyecto, que debería compilarse bien en Windows, está disponible en
InvDbf.MasterFields := 'Id'; // field on the customers table we are matching against our index
+
  [http://tony.maro.net/mod.php?mod=downloads&op=showcat&id=3&level=1 tony.maro.net]
  
 +
== See also ==
 +
*[[Example: TDbf (creating table and indexes, selecting of index)]]
  
= Programa de ejemplo - navegador DB=
+
==A tener en cuenta==
I've written a simple application that will use the TDbf to open and display database tables using the dbGrid control.  The Linux executable along with project sources which should compile fine in Windows is available from:  [http://tony.maro.net/mod.php?mod=downloads&op=showcat&id=3&level=1 tony.maro.net]
 
  
= A tener en cuenta=
+
&nbsp;&nbsp;&nbsp;Actualmente no se soporta la integridad referencial, ni los archivos .db encriptados internamente.
  
Currently there is no support for referential integrity, or internally encrypted .dbf files.
+
* Traducido por [[User:Mgsalvador|Usuario: Mgsalvador]]
 +
* Normalización de estilo y formato, y algún añadido menor, por [[User:Iskraelectrica|iskraelectrica (jldc)]]. 11 de junio de 2008.

Latest revision as of 01:29, 19 February 2020

Deutsch (de) English (en) español (es) français (fr) português (pt) русский (ru) 中文(中国大陆)‎ (zh_CN)


Resumen

   Esta tutoría trata sobre el desarrollo elemental de bases de datos usando el componente TDbf (de Micha Nelissen) con Lazarus. Hay disponible documentación adicional para TDbf. Esta página fue creada por Tony Maro, pero ¡se agradecen otras colaboraciones!

   En Lazarus, el componente DbfLaz utiliza el código de FPC TDbf.


Documentación

   Para documentación de TDbf en PDF ir a SourceForge. Puede ser útil tener este pdf junto con este documento durante su lectura.

Este artículo sirve como documentación adicional para nuevas características respecto a la documentación original.

Alternativas y problemas conocidos

   Alternativas para bases de datos embedias tales como Firebird embebido (ventaja: fácilmente escalable para cliente / servidor), SQLite (ventaja: fácil implementación), o ZMSQL (usa archivos CSV; ventaja: sólo necesita código Pascal).

   Problemas conocidos: El código TDbf careció de mantenedor por largo tiempo. Actualmente (marzo de 2013), tanto el proyecto upstream de Sourceforge (centrado en Delphi) como los desarrolladores de bases de datos FPC están de nuevo para arreglar errores de TDbf. Los errores corregidos en el trunk de FPC necesitarán fusionarse con la versión de SourceForge y viceversa.

Incidencias actuales: por favor ver bugs en el seguimiento de errores, especialmente http://bugs.freepascal.org/view.php?id=22177

Limitaciones

  • TDBF establece la codificación de la base de datos basándose en las configuraciones del lenguaje del sistema operativo (puedes establecer el tuyo estableciendo LanguageID; ver documentación). Mover una de estas bases de datos a un computador que no soporta dicha codificación puede ocasionar que la base de datos se quede como de solo lectura. Nota: investigar cuando esto se aplica a Tablelevel 7 (Visual DBase) y 25/30 (Foxpro/Visual Foxpro)
  • Ninguno de los formatos DBF utilizados soporta codicación Unicode (si UTF-8, UTF-16 o UTF-32). Podría haber una solución utilizando campos binarios, pero entonces perderiamos habilidades de reordenación, etc.
  • El indexado de un fichero DBase con [ixCaseInsensitive] no funciona actualmente.
  • No soporta todavía integridad referencial en formatos de fichero que si lo soportan (DBase VII, Visual FoxPro).
  • No soporta (ahora o bien para siempre) encriptación interna de ficheros .dbf: el mecanismo de encriptación de DbaseIV es bastante debil de todos modos. Por favor utiliza uno de los métodos de encriptación que se mencionan más abajo.

FPC 2.6.x y anteriores:

  • En procesadores ARM, el códigoTDBF es sabido que no funciona debido a incidencias de alineación de bus. Esto está siendo addressed en la versión de desarrollo/trunk.
  • Escoger el tablelevel (25) de FoxPro generará ficheros que no se podrán leer mediante drivers Visual Foxpro. Esto se ha solucionado en la versión de desarrollo/trunk de FPC.

No necesita instalación

  El paquete DbfLaz (dbflaz.lpk) viene instalado por defecto tanto en FPC como en Lazarus. Este paquete utiliza TDbf y sus unidades asociadas en Free Pascal Free Component Library. En otras palabras, no es necesario instalar nada si tienes justamente una versión reciente de Lazarus. Está situado en la carpeta lazarus/components/tdbf/.

¿Qué se puede hacer con TDbf?

   El componente TDbf proporciona a Lazarus (y otros entornos) acceso a tablas dBase y FoxPro. Permite la lectura, escritura y creación de tablas dBase III+, dBase IV, Visual dBase VII y FoxPro. Y sin necesitar librerías o gestores de bases de datos adicionales. Simplemente ponga el componente TDbf en su formulario y tendrá acceso inmediato a un entorno de bases de datos de para múltiples plataformas. TDbf funciona tanto en Windows como en Linux usando Lazarus.

Cómo crear una nueva tabla

   Como no hay todavía una aplicación "Database Desktop" para Lazarus, debemos crear las tablas de la base de datos mediante código, o utilizando herramientas externas.

Puedes probar esta aplicación (windows - funciona con wine): http://www.dirfile.com/cdbf_explorer.htm

Establecer la ruta de acceso

   Es recomendable crear una carpeta para sus aplicaciones de bases de datos. Esto simplifica la realización de copias de seguridad de los datos. Hay dos maneras de establecer la ruta de acceso. Puede fijar la ruta completa usando la propiedad FilePathFull, o puede establecer una ruta relativa a la ruta del programa con FilePath. Por ejemplo, estableciendo "FilePath" en tiempo de ejecución a "datos/" utilizaría una subcarpeta de datos dentro de la carpeta del archivo ejecutable. Fijar la propiedad "FilePathFull" a "/var/datos/" colocaría todo en esa carpeta, no teniendo en cuenta la ubicación del programa.

Elegir un tipo de tabla con TableLevel

   Por omisión, TDbf creará tablas dBase IV. Aunque son muy compatibles, hay características que puede desear usar que no están disponibles. Para poder utilizar campos autoincrementales, debe usar algo más nuevo. Los tipos de tabla posibles son:

Tipos de tablaTableLevel
dBase III+3
dBase IV4
Visual dBase VII7
FoxPro25


   Para elegir un tipo de tabla de el valor adecuado a la propiedad TableLevel.

Añadir campos

   La creación de campos para su nueva tabla en tiempo de ejecución se realiza como en Delphi. Una vez establecidas las propiedades FilePath, TableLevel, y TableName, hay que utilizar la propiedad FieldDefs para determinar su estructura. Por ejemplo:

 MyDbf.FilePathFull := '/ubicacion/para/mis/datos';
 MyDbf.TableLevel := 7;
 MyDbf.TableName := 'clientes.dbf'; // nota: ¿es realmente necesario .dbf?
 With MyDbf.FieldDefs do begin
   Add('Id', ftAutoInc, 0, True);
   Add('Nombre', ftString, 80, True);
 End;

   Los tipos de campo definidos son:

  • ftUnknown
  • ftString
  • ftSmallInt
  • ftInteger
  • ftWord
  • ftBoolean
  • ftFloat
  • ftCurrency (TableLevel 25)
  • ftBCD (TableLevel 25)
  • ftDate
  • ftTime
  • ftDateTime
  • ftBytes (TableLevel 25)
  • ftVarBytes
  • ftAutoInc (TableLevel 7 or 25)
  • ftBlob
  • ftMemo
  • ftGraphic
  • ftFmtMemo
  • ftParadoxOle
  • ftDBaseOle
  • ftTypedBinary
  • ftCursor
  • ftFixedChar
  • ftWideString
  • ftLargeInt
  • ftADT
  • ftArray
  • ftReference
  • ftDataSet
  • ftOraBlob
  • ftOraClob
  • ftVariant
  • ftInterface
  • ftIDispatch
  • ftGuid
  • ftTimeStamp
  • ftFMTBcd

   Los tipos que aparecen en negrita son los soportados en la actualidad.

¡Siga adelante y créela!

   Una vez que ha definido los campos deseará usarlos en su nueva tabla, puede seguir adelante y crearla con:

 MyDbf.CreateTable;

Añadir índices a una tabla

   Si su base de datos es bastante grande, deberá definir índices para hacer búsquedas más rápidas. Para cambiar la estructura de índices de una tabla, deberemos tener acceso exclusivo a la tabla -mientras los creamos.

 MyDbf.Exclusive := True;
 MyDbf.Open;

   Justo ahora, tenemos que añadir el índice.

 MyDbf.AddIndex('clienteid', 'Id', [ixPrimary, ixUnique]);
 MyDbf.AddIndex('nombrecliente','Nombre', [ixCaseInsensitive]);
 MyDbf.Close;

Lo unimos todo y ... ¡ya está!

   El siguiente ejemplo crea una tabla "clientes" mediante código. Esto, por supuesto, sólo es necesario hacerlo una vez para cada tabla, y de ahí en adelante, abrir la tabla, no crearla ;-)

 {Necesitamos que las siguientes unidades aparezcan en la clásula USES:}
 uses {otras unidades, } Dbf, db, Dbf_Common;
 { "Dbf" aparecerá, automáticamente, cuando pongamos el componente TDbf en el formulario...   }
 { pero necesitamos la unidad "db" para el objeto DataSet
 { y la unidad "Dbf_Common" para las definiciones de tipos de campo, por ejemplo        }
 var
   MyDbf: TDbf;
 begin
   MyDbf := TDbf.Create(nil);
   try
     
     MyDbf.FilePath := 'datos/';    // usamos una ruta de acceso relativa para la carpeta "datos"
     MyDbf.TableLevel := 7;         // utilizaremos tablas de tipo "Visual dBase VII"
     MyDbf.Exclusive := True;       // imprescindible para poder modificar la estructura añadiendo campos
     MyDbf.TableName := 'clientes.dbf';
     With MyDbf.FieldDefs do begin
       Add('Id', ftAutoInc, 0, True);
       Add('Nombre', ftString, 80, True);
     End;
     MyDbf.CreateTable;
     MyDbf.Open;
     MyDbf.AddIndex('clienteid', 'Id', [ixPrimary, ixUnique]);
     { añadimos un índice secundario }
     MyDbf.AddIndex('nombrecliente','Nombre', [ixCaseInsensitive]);
     MyDbf.Close;
   finally
     MyDbf.Free;
   end;

Archivos índice externos

   El componente TDBF también soporta índices secundarios que se almacenan en un archivo separado. Esto será útil cuándo la base de datos sea muy grande, al poder separar en varios archivos los distintos índices. Los archivos de índice secundarios se crean de forma muy parecida a los índices normales, pero con la adición de la extensión '.ndx ' en el nombre:

 MyDbf.AddIndex('nombrecliente.ndx','Nombre', [ixCaseInsensitive]);

   Estos índices no se gestionan de forma automática, por ello cada vez que se abre la tabla, se deberán cargar los archivos de índice que deseamos utilizar, usando el método OpenIndexFile, así:

 MyDbf.OpenIndexFile('nombrecliente.ndx');

   Por la misma razón los índices se empaquetan por separado, para ello utilizaremos el método CompactIndexFile, de esta forma:

 MyDbf.CompactIndexFile('nombrecliente.ndx');

   Y al dar el valor a la propiedad IndexName, para seleccionar el que estará activo, debemos incluir el nombre y la extensión:

 MyDbf.IndexName := 'nombrecliente.ndx';

Cómo enlazar TDbf a componentes de datos

   Los ejemplos anteriores muestran como crear una nueva tabla de base de datos mediante código. Usar la tabla es aún más simple.

   Los componentes de acceso a datos en Lazarus (como TDBEdit y TDbNavigator por ejemplo) se vinculan a un componente TDataSource mediante las propiedades DataSource y DataField. El componente TDataSource controla la comunicación entre el gestor de bases de datos y los componentes de acceso a datos. Un TDataSource se vincula al componente TDbf mediante su propiedad DataSet. La conexión sería así:

 TDbEdit------\
              |
 TDbEdit------|-->TDataSource-->TDbf
              |
 TDbNavigator-/

   No olvides establecer las propiedades FilePath (o FilePathFulll), TableLevel, y TableName del componente TDbf a los valores adecuados antes de activarlos mediante

 TDbf.Active := True;

   Se podría decir mucho más sobre programación con bases de datos en Lazarus, y yo recomendaría un buen libro de programación de bases de datos con Delphi porque los conceptos fundamentales son los mismos. Constantemente hago referencia a mi ejemplar de "Liberado Delphi 2" porque los conceptos y el código básico no han cambiado mucho en 8 años.

Empaquetar y reconstruir índices

   Cuando se borra un registro, realmente no desaparece físicamente del archivo que guarda la tabla. De vez en cuando debe empaquetar la tabla para eliminar realmente los registros y así recuperar ese espacio desaprovechado del archivo. Esto hay que hacerlo teniendo la tabla abierta en modo exclusivo.

 MyDbf.Exclusive := True;
 MyDbf.Open;
 MyDbf.PackTable;
 // reconstruimos todos los índices
 MyDbf.RegenerateIndexes;
 MyDbf.Close;
 MyDbf.Exclusive := False;

Relaciones de tabla principal

   La verdadera potencia de la programación de bases de datos comienza cuando tenemos múltiples tablas que se hacen referencia mutuamente. Mientras que TDbf aún no soporta la integridad referencial, si soporta una relación del tipo maestro/detalle entre componentes TDbf.

   Cuando hay dos tablas relacionadas, por ejemplo:

 [clientes]
 Id       <----\
 Nombre        |
 Telefono      |
 Direccion     |
               |  ClienteID en facturas hace referencia a un campo primario de clientes
 [facturas]    |
 Id            |
 Importe       |
 ClienteID   --\---|  * Campo indexado como "idxclienteid"

   Si desea mostrar todas las facturas para un cliente determinado, la tabla detalle (facturas) puede sincronizarse con la tabla principal (clientes) automáticamente.

   En el componente TDbf de facturas seleccione lo siguiente:

 InvDbf.IndexName := 'idxclienteid'; // campo que se emparejará con el campo ID de la tabla clientes                                     
 InvDbf.MasterSource := dsClientes;  // fuente de datos que se enlaza al componente TDbf de clientes
 InvDbf.MasterFields := 'Id';        // campo en la tabla clientes que emparejamos con nuestro índice

Cómo filtrar las Fechas vacías

   Voy a mostrar aquí como podemos filtrar las fechas en blanco con el componente de Lazarus TDbf.

   Considérese que en este ejemplo, el componente se denomina datos dbf1 y la base de datos tiene un campo, DT_ENCERRA, que indica cuando el caso se completó. Imagina también que necesitas crear un informe utilizando LazReport que enumera todos los casos que siguen pendientes, con el campo DT_ENCERRA en blanco.

   La forma más sencilla de hacerlo es utilizando el controlador de eventos OnFilterRecord y poner el siguiente código:

 if not dfb1.FieldByName('DT_ENCERRA').IsNull then Accept := False;

   Cuando ponemos el valor de Accept a False todos los registros que no cumplen con esa condición particular, no se tienen en cuenta, es decir, no se muestran en el informe.

   También es necesario poner la propiedad Dbf1.Filtered a True, pero fuera de este evento.

 dfb1.Filtered := True;

Cómo filtrar un valor con TDbf

   Supón que tienes una base de datos que identifica los productos con un código, por ejemplo, B019, y es necesario filtrar sólo aquellos productos que son de este código (B019, en este ejemplo) de manera que se genera un informe con LazReport. El componente se llama Dbf1. El campo que almacena el valor es "product_no"

   Tenemos dos maneras de filtrar. La primera sería la de utilizar el siguiente código:

 Dbf1.filter:= 'product_no "=" B019 "';

   Resulta que esto funciona muy bien con varios componentes, pero no funciona con LazReport.

   Para resolver el problema con LazReport puede utilizar el controlador de eventos OnFilterRecord y utilizar el siguiente código:

 Accept:= Copy(Trim(Dbf1.FieldByName('product_no').AsString),1,4)='B019';

   También es necesario poner la propiedad Dbf1.Filtered a True, pero fuera de este evento.

   Como se dijo antes, cuando el valor de Accept es false los registros no se tienen en cuenta y de esta manera puede evitar mostrar todos los productos con ese código en el informe LazReport

Programa de ejemplo - navegador DB

   He escrito un programa sencillo que utiliza el componente TDbf para abrir y mostrar tablas de bases de datos mediante el control dbGrid. El ejecutable Linux, junto con las fuentes del proyecto, que debería compilarse bien en Windows, está disponible en

 tony.maro.net

See also

A tener en cuenta

   Actualmente no se soporta la integridad referencial, ni los archivos .db encriptados internamente.