MS Access/es: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: MS Access/es
| Old | New | Line | |
|---|---|---|---|
| 1 | + | Esta página explica la forma de utilizar una base de datos de **Microsoft Access** haciendo uso de [[ODBCConn|ODBC]] y los componentes integrados de SQLDB de FPC. | |
| 2 | + | ||
| 3 | + | ## Detalles de MS Access | |
| 4 | + | ||
| 5 | + | ### UsePrimaryKeyAsKey | |
| 6 | + | ||
| 7 | + | En las propiedades de **TSQLQuery** será necesario poner el valor de UsePrimaryKeyAsKey a falso. | |
| 8 | + | ||
| 9 | + | ### Obtener la clave primaria autonumérica del elemento recién insertado | |
| 10 | + | ||
| 11 | + | Después de insertar datos, Access 2000 y superiores permiten obterner la clave primaria autonumérica recién insertada utilizando esta consulta: | |
| 12 | + | ||
| 13 | + | ``` SQL | |
| 14 | + | SELECT @@IDENTITY | |
| 15 | + | ``` | |
| 16 | + | ||
| 17 | + | ### Controladores de ODBC | |
| 18 | + | ||
| 19 | + | #### Windows | |
| 20 | + | ||
| 21 | + | Hay 2 controladores ODBC diferentes para Microsoft Access: | |
| 22 | + | ||
| 23 | + | - el controlador antiguo que solo puede usar archivos con formato .mdb, su nombre es "Microsoft Access driver (* .mdb)". Incluido en muchas versiones de Windows (desde Windows 2000 hasta hoy incluyendo Vista); descargable para versiones anteriores de Windows como parte de los componentes de MDAC o componentes de Jet. 32 bit solamente | |
| 24 | + | - el nuevo controlador que puede acceder a los archivos .mdb y .accdb, su nombre es "Microsoft Access driver (* .mdb, * .accdb)". Se puede descargar como "Microsoft Access Database Engine 2010 Redistributable"; disponible en 32 y 64 bit. | |
| 25 | + | ||
| 26 | + | Como de costumbre, cuando compilamos Lazarus/FPC a 32 bits usaremos controladores ODBC de 32 bits. Cuando compilemos Lazarus/FPC a 64 bits, usaremos controladores ODBC de 64 bits. | |
| 27 | + | ||
| 28 | + | #### Unix/Linux | |
| 29 | + | ||
| 30 | + | El [proyecto mdbtools](http://sourceforge.net/projects/mdbtools/) ofrece un soporte limitado para MS Accesss en linux. Incluye un controlador ODBC que puede ser utilizado. Para obtenerlo deberemos instalar paquetes como mdbtools, mdbtools-dev y mdbtools-gmdb | |
| 31 | + | ||
| 32 | + | Al menos en Debian, el nombre del controlador ODBC es "MDBTools". | |
| 33 | + | ||
| 34 | + | ## Instrucciones DSN basadas en archivos | |
| 35 | + | ||
| 36 | + | Un archivo DSN es simplemente un archivo donde se escriben las configuraciones de conexión. La razón para tener un archivo DSN es por si deseamos distribuir una conexión de fuente de datos a múltiples usuarios en diferentes sistemas sin tener que configurar un DSN para cada sistema. Por ejemplo, puedemos crear un DSN de archivo en una base de datos de informes en el escritorio. Entonces puedemos enviar el archivo a otros usuarios. Esos usuarios pueden guardar el archivo DSN en sus ordenadores y luego apuntar sus aplicaciones de informes al archivo DSN. | |
| 37 | + | ||
| 38 | + | Si desea utilizar un DSN basado en archivo con el controlador ODBC de SQLDB: | |
| 39 | + | ||
| 40 | + | ### Configurar el archivo DSN | |
| 41 | + | ||
| 42 | + | - Vamos a \[Fuentes de datos (ODBC)\] en las herramientas administrativas del panel de control. | |
| 43 | + | - Vamos al menú de la pestaña \[Archivo DSN\], hacemos clic en Agregar, luego seleccionamos \<Microsoft Access driver\>. | |
| 44 | + | - A continuación, buscamo la ruta actual del proyecto Lazarus para guardar ahí el archivo .DSN, ya que ese archivo dsn contendrá la configuración necesaria para acceder a su archivo de base de datos (.mdb). | |
| 45 | + | - Hacemos clic en Siguiente, luego en Finalizar (ahora hemos creado un nuevo archivo .dsn) que se utilizará en la TODBCConnection \[FileDSN\]. | |
| 46 | + | ||
| 47 | + | #### Contenido del archivo DSN | |
| 48 | + | ||
| 49 | + | Como muestra, un archivo DSN que hace referencia una base de datos de MS Access tendrá un aspecto similar a este: | |
| 50 | + | ||
| 51 | + | ```DOS | |
| 52 | + | [ODBC] | |
| 53 | + | DRIVER=Microsoft Access Driver (*.mdb) | |
| 54 | + | UID=admin | |
| 55 | + | UserCommitSync=Yes | |
| 56 | + | Threads=3 | |
| 57 | + | SafeTransactions=0 | |
| 58 | + | PageTimeout=5 | |
| 59 | + | MaxScanRows=8 | |
| 60 | + | MaxBufferSize=2048 | |
| 61 | + | FIL=MS Access | |
| 62 | + | DriverId=25 | |
| 63 | + | DefaultDir= | |
| 64 | + | DBQ=YOUR_msaccess.mdb | |
| 65 | + | ``` | |
| 66 | + | ||
| 67 | + | ### Configurar el proyecto para usar el DSN basado en archivos | |
| 68 | + | ||
| 69 | + | El uso de rejillas y otros controles vinculados a datos es similar a cualquier otro conector SQLDB, por lo que no se trata aquí. Como estamos utilizando una conexión ODBC, deberemos tener un objeto TODBCConnection. Propiedades de TOBDCConnection: | |
| 70 | + | ||
| 71 | + | - FileDSN = la ruta + nombre del archivo DSN guardado anteriormente, P. Ej. C:\milazarus\proyecto1\miArchivo.dsn | |
| 72 | + | - Nombre de usuario: admin (o el nombre de usuario que necesite si usa la seguridad de Access) este parámetro puede no ser necesario si no se usa seguridad de MS Access. | |
| 73 | + | ||
| 74 | + | No usaremos ninguna otra entrada en las propiedades. | |
| 75 | + | ||
| 76 | + | ## DSN de Sistema/Usuario | |
| 77 | + | ||
| 78 | + | Como se explica en el artículo de [[ODBCConn|ODBC]], también es posible usar los DSN de sistema o de usuario, donde los ajustes de conexión se definen en el panel de control de ODBC en lugar de almacenarse en un archivo. El objeto TODBCConnection tendrá este valor para la propiedad DatabaseName: \<name_of_your_DSN\>. | |
| 79 | + | ||
| 80 | + | ## Conexión sin DSN | |
| 81 | + | ||
| 82 | + | Como se explica en el artículo de ODBC , también puede crear una conexión sin DSN a su base de datos de Access donde puede especificar todos los parámetros de conexión en código, algo como: | |
| 83 | + | ||
| 84 | + | ``` pascal | |
| 85 | + | //Nota: estamos usando el nuevo controlador MS Access, probablemente también podríamos usar el anterior: | |
| 86 | + | conn.Driver:='Microsoft Access Driver (*.mdb, *.accdb)'; | |
| 87 | + | conn.Params.Add('DBQ=c:\somedirectory\test.mdb'); | |
| 88 | + | ...agregaremos los parámetros que queramos/necesitemos... | |
| 89 | + | ``` | |
| 90 | + | ||
| 91 | + | Aquí hay un ejemplo de cómo consultar una tabla en un archivo Access mdb utilizando TODBCConnection, TSQLTransaction y TSQLQuery (el archivo mdb estará en la misma carpeta que el ejecutable): | |
| 92 | + | ||
| 93 | + | ``` pascal | |
| 94 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 95 | + | begin | |
| 96 | + | //connection | |
| 97 | + | ODBCConnection1.Driver := 'Microsoft Access Driver (*.mdb, *.accdb)'; | |
| 98 | + | ODBCConnection1.Params.Add('DBQ=.\prueba.mdb'); // o especificamos la ruta absoluta al archivo mdb | |
| 99 | + | ODBCConnection1.Params.Add('Locale Identifier=1031'); | |
| 100 | + | ODBCConnection1.Params.Add('ExtendedAnsiSQL=1'); | |
| 101 | + | ODBCConnection1.Params.Add('CHARSET=ansi'); | |
| 102 | + | ODBCConnection1.Connected := True; | |
| 103 | + | ODBCConnection1.KeepConnection := True; | |
| 104 | + | ||
| 105 | + | //transaction | |
| 106 | + | SQLTransaction1.DataBase := ODBCConnection1; | |
| 107 | + | SQLTransaction1.Action := caCommit; | |
| 108 | + | SQLTransaction1.Active := True; | |
| 109 | + | ||
| 110 | + | SQLQuery1.DataBase := ODBCConnection1; | |
| 111 | + | SQLQuery1.UsePrimaryKeyAsKey := False; | |
| 112 | + | SQLQuery1.SQL.Text := 'select * from Clientes'; | |
| 113 | + | SQLQuery1.Open; | |
| 114 | + | end; | |
| 115 | + | ``` | |
| 116 | + | ||
| 117 | + | ## Código de ejemplo | |
| 118 | + | ||
| 119 | + | ### Lazarus: controles de datos en formularios | |
| 120 | + | ||
| 121 | + | Muestra de código fuente funcional: (Updated2_with_add_delete_update) <http://www.mediafire.com/file/ne1jx3zpnwzefq3/msaccesstest2.zip> | |
| 122 | + | ||
| 123 | + | ``` pascal | |
| 124 | + | unit Unit1; | |
| 125 | + | ||
| 126 | + | {$mode objfpc}{$H+} | |
| 127 | + | ||
| 128 | + | interface | |
| 129 | + | ||
| 130 | + | uses | |
| 131 | + | Classes, SysUtils, odbcconn, sqldb, db, FileUtil, LResources, Forms, Controls, | |
| 132 | + | Graphics, Dialogs, DBGrids, DbCtrls, StdCtrls, Printers, PrintersDlgs; | |
| 133 | + | ||
| 134 | + | type | |
| 135 | + | ||
| 136 | + | { TForm1 } | |
| 137 | + | ||
| 138 | + | TForm1 = class(TForm) | |
| 139 | + | Button1: TButton; | |
| 140 | + | Button2: TButton; | |
| 141 | + | Button3: TButton; | |
| 142 | + | Button4: TButton; | |
| 143 | + | Datasource1: TDatasource; | |
| 144 | + | DBEdit1: TDBEdit; | |
| 145 | + | DBEdit2: TDBEdit; | |
| 146 | + | DBGrid1: TDBGrid; | |
| 147 | + | ODBCConnection1: TODBCConnection; | |
| 148 | + | PrintDialog1: TPrintDialog; | |
| 149 | + | SQLQuery1: TSQLQuery; | |
| 150 | + | SQLTransaction1: TSQLTransaction; | |
| 151 | + | procedure Button1Click(Sender: TObject); | |
| 152 | + | procedure Button2Click(Sender: TObject); | |
| 153 | + | procedure Button3Click(Sender: TObject); | |
| 154 | + | procedure Button4Click(Sender: TObject); | |
| 155 | + | procedure FormCloseQuery(Sender: TObject; var CanClose: boolean); | |
| 156 | + | procedure FormShow(Sender: TObject); | |
| 157 | + | private | |
| 158 | + | { private declarations } | |
| 159 | + | procedure PrintDbGrid(dbGrid:TdbGrid); | |
| 160 | + | public | |
| 161 | + | { public declarations } | |
| 162 | + | end; | |
| 163 | + | ||
| 164 | + | var | |
| 165 | + | Form1: TForm1; | |
| 166 | + | ||
| 167 | + | implementation | |
| 168 | + | ||
| 169 | + | { TForm1 } | |
| 170 | + | ||
| 171 | + | procedure TForm1.FormShow(Sender: TObject); | |
| 172 | + | begin | |
| 173 | + | //connection | |
| 174 | + | ODBCConnection1.FileDSN := ExtractFilePath(Application.ExeName) + 'file.dsn'; | |
| 175 | + | ODBCConnection1.Connected := True; | |
| 176 | + | ODBCConnection1.KeepConnection := True; | |
| 177 | + | ||
| 178 | + | //transaction | |
| 179 | + | SQLTransaction1.DataBase := ODBCConnection1; | |
| 180 | + | SQLTransaction1.Action := caCommit; | |
| 181 | + | SQLTransaction1.Active := True; //not applied to ms access(false) | |
| 182 | + | ||
| 183 | + | SQLQuery1.DataBase := ODBCConnection1; | |
| 184 | + | SQLQuery1.UsePrimaryKeyAsKey := False; | |
| 185 | + | ||
| 186 | + | SQLQuery1.SQL.Text := 'select * from table1'; | |
| 187 | + | ||
| 188 | + | // :id is the parameter for the field name id | |
| 189 | + | SQLQuery1.deleteSQL.Text := 'delete from table1 where id=:id'; | |
| 190 | + | //:name is the parameter for the field name name | |
| 191 | + | SQLQuery1.updateSQL.Text := 'update table1 set name=:name where id=:id'; | |
| 192 | + | ||
| 193 | + | DataSource1.DataSet := SQLQuery1; | |
| 194 | + | DBGrid1.DataSource := DataSource1; | |
| 195 | + | DBGrid1.ReadOnly := true; | |
| 196 | + | ||
| 197 | + | DBEdit1.DataField := 'id'; | |
| 198 | + | DBEdit1.DataSource := DataSource1; | |
| 199 | + | DBEdit2.DataField := 'name'; | |
| 200 | + | DBEdit2.DataSource := DataSource1; | |
| 201 | + | ||
| 202 | + | SQLQuery1.Open; | |
| 203 | + | end; | |
| 204 | + | ||
| 205 | + | function MulDiv(nNumber, nNumerator, nDenominator: Integer): Integer; | |
| 206 | + | begin | |
| 207 | + | Result:=Round(int64(nNumber)*int64(nNumerator)/nDenominator); | |
| 208 | + | end; | |
| 209 | + | procedure TForm1.PrintDbGrid(dbGrid:TdbGrid); | |
| 210 | + | const | |
| 211 | + | LeftMargin = 0.05; | |
| 212 | + | TopMargin = 0.05; | |
| 213 | + | BottomMargin = 0.05; | |
| 214 | + | var | |
| 215 | + | i: integer; | |
| 216 | + | x,y: integer; | |
| 217 | + | begin | |
| 218 | + | if PrintDialog1.Execute then | |
| 219 | + | begin | |
| 220 | + | Printer.BeginDoc; | |
| 221 | + | Printer.Canvas.Font.Size := 12; | |
| 222 | + | ||
| 223 | + | y := Round(TopMargin*Printer.PageHeight); | |
| 224 | + | dbGrid.DataSource.DataSet.First; | |
| 225 | + | while not dbGrid.DataSource.DataSet.Eof do | |
| 226 | + | begin | |
| 227 | + | x := Round(LeftMargin*Printer.PageWidth); | |
| 228 | + | for i := 0 to dbGrid.DataSource.DataSet.FieldCount-1 do | |
| 229 | + | begin | |
| 230 | + | printer.Canvas.TextOut(x,y,dbGrid.DataSource.DataSet.Fields[i].AsString); | |
| 231 | + | x := x + MulDiv(dbGrid.Columns[i].Width,72, dbGrid.Width); | |
| 232 | + | end; | |
| 233 | + | dbGrid.DataSource.DataSet.Next; | |
| 234 | + | y := y + printer.Canvas.TextHeight('A'); | |
| 235 | + | if y > (1-TopMargin-BottomMargin)* Printer.PageHeight then | |
| 236 | + | begin | |
| 237 | + | y := Round(TopMargin*Printer.PageHeight); | |
| 238 | + | Printer.NewPage; | |
| 239 | + | end; | |
| 240 | + | end; | |
| 241 | + | Printer.EndDoc; | |
| 242 | + | end | |
| 243 | + | else | |
| 244 | + | Form1.caption := 'NO PRINTER INSTALLED'; | |
| 245 | + | end; | |
| 246 | + | ||
| 247 | + | procedure TForm1.Button1Click(Sender: TObject); | |
| 248 | + | begin | |
| 249 | + | PrintDbGrid(DBGrid1); | |
| 250 | + | end; | |
| 251 | + | ||
| 252 | + | procedure TForm1.Button2Click(Sender: TObject); | |
| 253 | + | begin | |
| 254 | + | if button2.Caption = 'new' then | |
| 255 | + | begin | |
| 256 | + | SQLQuery1.Insert; | |
| 257 | + | button2.Caption := 'save'; | |
| 258 | + | exit | |
| 259 | + | end | |
| 260 | + | else | |
| 261 | + | begin | |
| 262 | + | if (dbedit1.Text = '') or (dbedit2.Text = '') | |
| 263 | + | then | |
| 264 | + | begin | |
| 265 | + | SQLQuery1.Cancel; | |
| 266 | + | end | |
| 267 | + | else | |
| 268 | + | begin | |
| 269 | + | if SQLQuery1.State = dsInsert then | |
| 270 | + | begin | |
| 271 | + | SQLQuery1.Post; | |
| 272 | + | SQLQuery1.ApplyUpdates; | |
| 273 | + | Form1.caption := 'ADDED'; | |
| 274 | + | end; | |
| 275 | + | end; | |
| 276 | + | end; | |
| 277 | + | button2.Caption := 'new'; | |
| 278 | + | end; | |
| 279 | + | ||
| 280 | + | procedure TForm1.Button3Click(Sender: TObject); | |
| 281 | + | begin | |
| 282 | + | if SQLQuery1.RecordCount>0 then | |
| 283 | + | begin | |
| 284 | + | SQLQuery1.Delete; | |
| 285 | + | SQLQuery1.ApplyUpdates; | |
| 286 | + | ||
| 287 | + | //REMOVED or ADD this 2 lines if there is a problem in your SQLdB | |
| 288 | + | //THESE 2 lines apparently work around a bug in SQLdB for MS_Access dataBase' | |
| 289 | + | //**** missing reference to bugtracker item; please create a bugtracker item | |
| 290 | + | //SQLQuery1.Close; | |
| 291 | + | //SQLQuery1.Open; | |
| 292 | + | ||
| 293 | + | Form1.caption := 'DELETED'; | |
| 294 | + | end; | |
| 295 | + | end; | |
| 296 | + | ||
| 297 | + | procedure TForm1.Button4Click(Sender: TObject); | |
| 298 | + | begin | |
| 299 | + | if SQLQuery1.RecordCount>0 then | |
| 300 | + | begin | |
| 301 | + | SQLQuery1.Edit; | |
| 302 | + | SQLQuery1.Post; | |
| 303 | + | Sqlquery1.ApplyUpdates; | |
| 304 | + | Form1.caption := 'UPDATED'; | |
| 305 | + | end; | |
| 306 | + | end; | |
| 307 | + | ||
| 308 | + | procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: boolean); | |
| 309 | + | begin | |
| 310 | + | SQLQuery1.Close; | |
| 311 | + | CanClose := True; | |
| 312 | + | end; | |
| 313 | + | ||
| 314 | + | initialization | |
| 315 | + | {$I unit1.lrs} | |
| 316 | + | ||
| 317 | + | end. | |
| 318 | + | ``` | |
| 319 | + | ||
| 320 | + | ### Crear una base de datos 'al vuelo' desde el programa | |
| 321 | + | ||
| 322 | + | Con cualquiera de los controladores ODBC, es posible crear bases de datos de Microsoft Access mediante programación. (Nota: el manejo de errores no se ha probado; actualiza la página si lo probaste) | |
| 323 | + | ||
| 324 | + | Programa de ejemplo: | |
| 325 | + | ||
| 326 | + | ``` pascal | |
| 327 | + | program CreateAccessDb; | |
| 328 | + | ||
| 329 | + | {$mode objfpc}{$H+} | |
| 330 | + | ||
| 331 | + | uses | |
| 332 | + | {$IFDEF UNIX}{$IFDEF UseCThreads} | |
| 333 | + | cthreads, | |
| 334 | + | {$ENDIF}{$ENDIF} | |
| 335 | + | Classes, sysutils, | |
| 336 | + | LCLType; | |
| 337 | + | ||
| 338 | + | Const | |
| 339 | + | ODBC_ADD_DSN=1; | |
| 340 | + | ODBC_CONFIG_DSN=2; | |
| 341 | + | ODBC_REMOVE_DSN=3; | |
| 342 | + | ODBC_ADD_SYS_DSN=4; | |
| 343 | + | ODBC_CONFIG_SYS_DSN=5; | |
| 344 | + | ODBC_REMOVE_SYS_DSN=6; | |
| 345 | + | ODBC_REMOVE_DEFAULT_DSN=7; | |
| 346 | + | function SQLConfigDataSource(hwndParent: Integer; fRequest: Integer; | |
| 347 | + | lpszDriverString: PChar; lpszAttributes: PChar): Integer; stdcall; external 'odbccp32.dll'; | |
| 348 | + | function SQLInstallerError(iError: integer; pfErrorCode: PInteger; lpszErrorMsg: string; cbErrorMsgMax: integer; pcbErrorMsg: PInteger): integer; stdcall; external 'odbccp32.dll'; | |
| 349 | + | ||
| 350 | + | function CreateAccessDatabase(DatabaseFile: string): boolean; | |
| 351 | + | var | |
| 352 | + | DBPChar: PChar; | |
| 353 | + | Driver: PChar; | |
| 354 | + | ErrorCode, ResizeErrorMessage: integer; | |
| 355 | + | ErrorMessage: PChar; | |
| 356 | + | retCode: integer; | |
| 357 | + | begin | |
| 358 | + | driver := 'Microsoft Access Driver (*.mdb, *.accdb)'; | |
| 359 | + | { With this driver, | |
| 360 | + | CREATE_DB/CREATE_DBV12 will create an .accdb format database; | |
| 361 | + | CREATE_DBV4 will create an mdb | |
| 362 | + | http://stackoverflow.com/questions/9205633/how-do-i-specify-the-odbc-access-driver-format-when-creating-the-database | |
| 363 | + | } | |
| 364 | + | DBPChar:=PChar('CREATE_DBV4="'+DatabaseFile+'"'); | |
| 365 | + | retCode := SQLConfigDataSource(Hwnd(nil), ODBC_ADD_DSN, Driver, DBPChar); | |
| 366 | + | if retCode<>0 then | |
| 367 | + | begin | |
| 368 | + | //try alternate driver | |
| 369 | + | Driver := 'Microsoft Access Driver (*.mdb)'; | |
| 370 | + | DBPChar:=PChar('CREATE_DB="'+DatabaseFile+'"'); | |
| 371 | + | retCode := SQLConfigDataSource(Hwnd(nil), ODBC_ADD_DSN, Driver, DBPChar); | |
| 372 | + | end; | |
| 373 | + | if retCode=0 then | |
| 374 | + | begin | |
| 375 | + | result:=true; | |
| 376 | + | end | |
| 377 | + | else | |
| 378 | + | begin | |
| 379 | + | result:=false; | |
| 380 | + | ErrorCode:=0; | |
| 381 | + | ResizeErrorMessage:=0; | |
| 382 | + | // todo: verify how the DLL is called - use pointers?; has not been tested. | |
| 383 | + | GetMem(ErrorMessage,512); | |
| 384 | + | try | |
| 385 | + | SQLInstallerError(1, @ErrorCode, ErrorMessage, SizeOf(ErrorMessage), @ResizeErrorMessage); | |
| 386 | + | finally | |
| 387 | + | FreeMem(ErrorMessage); | |
| 388 | + | end; | |
| 389 | + | raise Exception.CreateFmt('Error creating Access database: %s', [ErrorMessage]); | |
| 390 | + | end; | |
| 391 | + | end; | |
| 392 | + | ||
| 393 | + | begin | |
| 394 | + | writeln('Result: '); | |
| 395 | + | write(CreateAccessDatabase('d:\cop\t\bla.mdb')); | |
| 396 | + | end. | |
| 397 | + | ``` | |
| 398 | + | ||
| 399 | + | ### Problemas con los diferentes conjuntos de caracteres | |
| 400 | + | ||
| 401 | + | Las bases de datos de las veresiones antiguas de Access están codificadas usando un juego de caracteres ANSI (las nuevas probablemente utilicen UNICODE). Por lo tanto, los caracteres que no son ASCII no se muestran correctamente en un DBGrid y otros controles de datos. Esto puede solucionarse adjuntando manejadores a los eventos OnGetText y OnSetText del conjunto de datos después de abrir la BD: | |
| 402 | + | ||
| 403 | + | ``` pascal | |
| 404 | + | uses | |
| 405 | + | lconvencoding; | |
| 406 | + | ||
| 407 | + | procedure TForm1.SQLQuery1AfterOpen(DataSet: TDataSet); | |
| 408 | + | var | |
| 409 | + | i: Integer; | |
| 410 | + | begin | |
| 411 | + | for i:=0 to DataSet.Fields.Count-1 do | |
| 412 | + | begin | |
| 413 | + | if DataSet.Fields[i].DataType=ftString then | |
| 414 | + | begin | |
| 415 | + | DataSet.Fields[i].OnGetText := @ConvertFromDB; | |
| 416 | + | DataSet.Fields[i].OnSetText := @ConvertToDB; | |
| 417 | + | end; | |
| 418 | + | end; | |
| 419 | + | end; | |
| 420 | + | ||
| 421 | + | procedure TForm1.ConvertFromDB(Sender: TField; var aText: string; DisplayText: Boolean); | |
| 422 | + | begin | |
| 423 | + | if not Sender.IsNull then | |
| 424 | + | aText := WinCPToUTF8(Sender.AsString); // if encoded in windows default code page | |
| 425 | + | end; | |
| 426 | + | ||
| 427 | + | procedure TForm1.ConvertToDB(Sender: TField; const aText: string); | |
| 428 | + | begin | |
| 429 | + | if aText <> '' then | |
| 430 | + | Sender.Value := UTF8ToWinCP(aText); | |
| 431 | + | end; | |
| 432 | + | ``` | |
| 433 | + | ||
| 434 | + | ## Base de datos de ejemplo | |
| 435 | + | ||
| 436 | + | Microsoft Access se distyribuye con la base de datos de ejemplo Northwind. | |
| 437 | + | ||
| 438 | + | Si únicamente disponemos de Access Runtime, se puede usar esta base de datos alternativa del proyecto Mondial como base de datos de prueba: \[1\] [1](http://databases.about.com/od/sampleaccessdatabases/a/Microsoft-Access-Sample-Database-Countries-Cities-And-Provinces.htm) | |
| 439 | + | ||
| 440 | + | ## Ver también | |
| 441 | + | ||
| 442 | + | - [[ODBCConn]] El conector ODBC que este artículo utilizamos | |
| 443 | + | ||
| 444 | + | --- | |
| 445 | + | *From the Free Pascal wiki, page "MS Access/es", as it stood on 2020-02-20 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* | |
| 446 | + | Category: Castellano | |
| 447 | + | Category: Español |
