Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Otros entornos y lenguajes > Lazarus, FreePascal, Kylix, etc.
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 08-08-2016
Avatar de anubis
anubis anubis is offline
Miembro
 
Registrado: mar 2007
Posts: 852
Poder: 11
anubis Va por buen camino
forma correcta de acceder y guardar en firebird con ibx

Hola amigos,

Le ando dando vueltas a si estoy programando correctamente.
Ya hice algunos meses algunas aplicaciones usando lazarus, componentes zeos y firebird. En principio todo funcionaba bien, pero despues de unos meses, me comentan que, en algunas ocasiones, no esta guardando los registros.En otros casos, he usado componentes ibx para lazarus, y hace exactamente lo mismo.
Lo primero que hago, es crear un datamodule y ahi le meto la basededatos, un dataset y un datasource. Los tres ligados. Con eso ya puedo acceder sin problemas.
Código Delphi [-]
 fmodulodatos.ibproductos.SelectSQL.clear;
   fmodulodatos.ibproductos.selectsql.Text:='select * from productos order by nombre_producto';
   fmodulodatos.ibproductos.Open;
   fmodulodatos.ibcomprasdetalle.SelectSQL.clear;
   fmodulodatos.ibcomprasdetalle.SelectSQL.Text:='select * from comprasdetalle where id_compra=:idcompra';
   fmodulodatos.ibcomprasdetalle.ParamByName('idcompra').asinteger:=idcompra;
   fmodulodatos.ibcomprasdetalle.Open;

Tambien, sino quiero alterar el ibdataset de productos por ejemplo, lo que hay generar un ibdataset temporal al que le asigno la tabla productos con otros parametros para visualizar en un dbgrid por ejemplo.

A la hora de guardar, simplemente aplico lo siguiente:

Código Delphi [-]
with fmodulodatos do
   begin
   ibcomprasdetalle.insert;
   ibcomprasdetalle.FieldByName('id_compra').asinteger:=idcompra;
   ibcomprasdetalle.fieldbyname('id_producto').asinteger:=dblookupproducto.KeyValue;
   ibcomprasdetalle.fieldbyname('cantidad').asinteger:=icantidad;
   ibcomprasdetalle.fieldbyname('preciocoste').asfloat:=preciocost;
   ibcomprasdetalle.fieldbyname('lote').asstring:=lote.Text;
   ibcomprasdetalle.fieldbyname('fecha_caducidad').asdatetime:=datefechacaducidad.Date;
   ibcomprasdetalle.Post;
INVENTARIO(DBLOOKUPPRODUCTO.KEYVALUE,icantidad); // es otra procedure donde hago lo mismo con inventarios
   precios(dblookupproducto.KeyValue,preciocost); // otra procedure donde hago lo mismo con precios
   ibtransaction1.CommitRetaining;  
end;

No se que mas hay que hacer para que no de problemas posteriores.
En las tablas tengo asignados los triggers, generators y en cada tabla, si hace falta, añado indices ademas de los que se generan solos por la primary key.

Q estoy haciendo mal.
Responder Con Cita
  #2  
Antiguo 08-08-2016
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 27.311
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Los registros no se pueden borrar porque pongas componentes en un datamodule o en un form, tendrás que revisar posts, transacciones, etc.
Aparte de eso, en el datamodule principal te aconsejo poner la conexión a la base de datos y la transacción. Luego, puedes tener un datamodule independiente para compras, otro para ventas, otro para 'otras cosas'...
El datasource lo pones en el form donde está el dbgrid que quieras mostrar.
Eso es basicamente.
Responder Con Cita
  #3  
Antiguo 08-08-2016
Avatar de anubis
anubis anubis is offline
Miembro
 
Registrado: mar 2007
Posts: 852
Poder: 11
anubis Va por buen camino
Gracias por contestar Casimiro Notevi,
Si, lo que hago es eso, poner una base de datos, la transaccion, un dataset y un datasource todo en un datamodule.
Por lo que me dices, puedo poner datamodules separados y los datasource acompañando en los forms donde vayan por ejemplo los dbgrid.
De todas formas, ponerlos juntos o separados no debe de influir solo seria por estetica de diseño?.

Entiendo ademas que, segun lo que he descrito en el primer mensaje del post, esta correcta la forma: insertar o edit, asignar y postear, despues tan solo hace un commitretaining. No debiera de haber problemas.

Gracias de nuevo.
Responder Con Cita
  #4  
Antiguo 08-08-2016
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 27.311
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por anubis Ver Mensaje
De todas formas, ponerlos juntos o separados no debe de influir solo seria por estetica de diseño?.
No es por estética, es porque la conexión a la base de datos y transacción sirve para todo el programa y, sin embargo, el datasource de un dbgrid es solamente para ese dbgrid que está en un form. Y es más cómodo asignarlo porque no hay que incluir en el uses el datamodule, ni tampoco hay que escribir más código innecesario: datamodulexx.datasource.....
Cita:
Empezado por anubis Ver Mensaje
Entiendo ademas que, segun lo que he descrito en el primer mensaje del post, esta correcta la forma: insertar o edit, asignar y postear, despues tan solo hace un commitretaining. No debiera de haber problemas.
Es muy difícil poder aconsejar porque no podemos ver nada más, ni siquiera sabemos qué parámetros has puesto en las transacciones.
Responder Con Cita
  #5  
Antiguo 09-08-2016
Avatar de anubis
anubis anubis is offline
Miembro
 
Registrado: mar 2007
Posts: 852
Poder: 11
anubis Va por buen camino
Ah perdon,
en transaction tengo:
defaultaction->tacommitretaining

en parametros
read_commited
rec_version
nowait

del resto, no se que mas opciones comentaros.
Responder Con Cita
  #6  
Antiguo 09-08-2016
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 27.311
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
En principio, todo bien, tendrás que verificar exactamente qué datos son esos que se pierden y verificar esa parte de tu código.
Porque perderse datos es imposible, salvo que los borren a propósito.
Responder Con Cita
  #7  
Antiguo 21-02-2017
Avatar de anubis
anubis anubis is offline
Miembro
 
Registrado: mar 2007
Posts: 852
Poder: 11
anubis Va por buen camino
Hola.
Perdón que reabra este post después de tanto tiempo de inactividad pero digamos que estuve ausente del tema por algunos problemas.

Retomando lo que preguntaba y, viendo que Casimiro Notevi ya me contestó que, en principio, todo se veía más o menos bien, quería añadir lo siguiente:

Si tengo dos tablas, una de productos y otra de precios.
Cuando doy de alta un producto, lo que hago es lo siguiente:

Bueno, lo primero es tener asignadas las tablas y abiertas.

Código Delphi [-]
with modulodatos do
begin  
   ibproductos.SelectSQL.clear;
   ibproductos.selectsql.Text:='select * from productos';
   ibproductos.Open;

   ibprecios.SelectSQL.clear;
   ibprecios.selectsql.Text:='select * from precios';
   ibprecios.Open;
end;

Código Delphi [-]
with modulodatos do
begin
   ibproductos.insert;
   ibproductos.fieldbyname('codigo_barras').asstring;
   ibproductos.fieldbyname('nombre_producto').asstring;
   ibproductos.post;
   ibtransaction1.CommitRetaining;  

   ibtemporal.selectsql.clear;
   ibtemporal selectsql.text:='select max(id_producto) as ultimo_id from productos'; // para sacar el último producto que acabo de añadir.
   ibtemporal.open;
   
   ultimo_producto:=ibtemporal.fieldbyname('ultimo_id').asstring;
   
   ibprecios.insert;
   ibprecios.fieldbyname('id_producto').asinteger:=ultimo_producto;
   ibprecios.fieldbyname('precio_costo').asfloat:=precio_costo;
   ibprecios.post;
   
   ibtransaction1.commitretaining;

end;

En principio eso funciona sin mayor problema, imagino que no es la mejor manera de programarlo.

Sólo tengo el problema si quiero hacer esto:

Código Delphi [-]
producto_registrado:=ibproducto.fieldbyname('id_producto').asinteger;
nombre_producto:=ibproducto.fieldbyname('nombre_producto').asstring;

Es el último producto que acabo de añadir.
El id_producto aparece en 0 pero el nombre_producto si me lo devuelve.
Si le añado un dbgrid para probar, el id_producto aparece vacío.
Ya he probado a cerrar la tabla y vuelto a abrir, a refrescarla, ... Pero con los mismos resultados.

La idea de todo lo anterior, es poder insertar un producto y tambien su precio en otra tabla.

Perdonen que ande preguntando sobre estas cosas, sé que son cosas muy básicas pero no consigo resolverlas.

Gracias.
Responder Con Cita
  #8  
Antiguo 21-02-2017
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.777
Poder: 8
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Cuando grabas el precio, en el medio pedís el último ID del producto. Ese paso se hace correctamente? Es decir, se graba el ID correspondiente, o te graba 0? Estás usando un generador para el ID?
Responder Con Cita
  #9  
Antiguo 21-02-2017
Avatar de anubis
anubis anubis is offline
Miembro
 
Registrado: mar 2007
Posts: 852
Poder: 11
anubis Va por buen camino
Gracias por contestar .

Si, al pedir el ultimo id si lo saca correctamente, de momento no he tenido problemas con eso.

El problema lo tengo cuando quiero sacar el id directamente de la tabla productos de ese registro. Algo me debe de faltar en la transaccion, la tabla, la base de datos o no se, para que actualice id_producto.

O no se como debiera de hacerse.
Responder Con Cita
  #10  
Antiguo 22-02-2017
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 9.736
Poder: 27
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola.

De tu código me surge una duda:
Código Delphi [-]
  with modulodatos do
  begin
   ibproductos.insert;
   ibproductos.fieldbyname('codigo_barras').asstring;
   ibproductos.fieldbyname('nombre_producto').asstring;
   ibproductos.post;
   ibtransaction1.CommitRetaining;
¿ No le asignas un valor a la columna ID_PRODUCTOS de la tabla productos antes de guardar ?

Cita:
Empezado por anubis Ver Mensaje
...
Si, al pedir el ultimo id si lo saca correctamente, de momento no he tenido problemas con eso.

El problema lo tengo cuando quiero sacar el id directamente de la tabla productos de ese registro. Algo me debe de faltar en la transaccion, la tabla, la base de datos o no se, para que actualice id_producto.
Si al consultar el último ID lo obtenes bién, ¿ Seguro que estas posicionado en el registro correcto cuando consultas de forma directa el valor del campo ?

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #11  
Antiguo 28-02-2017
Avatar de anubis
anubis anubis is offline
Miembro
 
Registrado: mar 2007
Posts: 852
Poder: 11
anubis Va por buen camino
Gracias por las respuestas,

Uso un generador asi que no asigno ningun id_producto a "mano".
Respecto a si posiciono bien, ya lo he resuelto, tuve que usar un locate para posicionarme.
Y, sobre sacar el id_producto despues de hacer post y commitretaining, no tengo más remedio que cerrar la tabla y volverla a abrir.

Esto es normal?. Cada vez, cerrar y abrir tablas?
Responder Con Cita
  #12  
Antiguo 28-02-2017
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.777
Poder: 8
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Yo utilizo la clausula RETURNING del INSERT INTO para que me devuelva el valor de Id que el generador le dio al registro que estoy insertado. De esta manera evitas problemas de concurrencia y hasta es mas eficiente, puesto que en una sola operacion insertas y obtenes el id que necesitas
Responder Con Cita
  #13  
Antiguo 28-02-2017
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 27.311
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por AgustinOrtu Ver Mensaje
Yo utilizo la clausula RETURNING del INSERT INTO para que me devuelva el valor de Id que el generador le dio al registro que estoy insertado. De esta manera evitas problemas de concurrencia y hasta es mas eficiente, puesto que en una sola operacion insertas y obtenes el id que necesitas
Responder Con Cita
  #14  
Antiguo 01-03-2017
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 9.736
Poder: 27
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola.
Cita:
Empezado por anubis Ver Mensaje
Uso un generador asi que no asigno ningun id_producto a "mano".
Entonces, para obtener el ID recién generado, sin alterar su valor:
Código SQL [-]
SELECT GEN_ID(G_TUTABLA, 0) AS NEXT_ID FROM RDB$DATABASE
Y para obtener el próximo ID ( incrementando su valor ):
Código SQL [-]
SELECT GEN_ID(G_TUTABLA, 1) AS NEXT_ID FROM RDB$DATABASE
Cita:
Empezado por anubis Ver Mensaje
Y, sobre sacar el id_producto despues de hacer post y commitretaining, no tengo más remedio que cerrar la tabla y volverla a abrir.
No necesariamente. Podes obtener el último ID de forma directa, o haciéndote una función, independientemente de si la tabla está abierta o cerrada:
Código Delphi [-]
function Tmodulodatos.TuTablaGetLastID: Int64;
begin
  IBQuery1.Close;
  IBQuery1.SQL.Text := 'SELECT GEN_ID(G_TUTABLA, 0) AS NEXT_ID FROM RDB$DATABASE';
  IBQuery1.Open;
  Result := IBQuery1.FieldByName('NEXT_ID').AsInteger;
  IBQuery1.Close;
end;
Y claro que también como te indica Agustín, al momento de realizar la inserción.

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #15  
Antiguo 01-03-2017
Avatar de anubis
anubis anubis is offline
Miembro
 
Registrado: mar 2007
Posts: 852
Poder: 11
anubis Va por buen camino
Gracias.

Pues si, son opciones a tener en cuenta y las voy a probar .

De todas formas, el problema que tengo es que, despues de insertar un nuevo registro, si pido ese registro el, id_producto por ejemplo, me devuelve 0 y en el dbgrid me sale en blanco.
Lo soluciono cerrando la tabla y abriendola de nuevo.
Ya probe con refresh y tampoco me lo resuelve.
Responder Con Cita
  #16  
Antiguo 01-03-2017
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 9.736
Poder: 27
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola.
Cita:
Empezado por anubis Ver Mensaje
...
De todas formas, el problema que tengo es que, despues de insertar un nuevo registro, si pido ese registro el, id_producto por ejemplo, me devuelve 0 y en el dbgrid me sale en blanco.
Lo soluciono cerrando la tabla y abriendola de nuevo.
Ya probe con refresh y tampoco me lo resuelve.
Es que cuando Firebird incrementa el generador desde un trigger (vg. BEFORE INSERT) el DataSet no se entera del nuevo valor asignado hasta que lo cierres y abras nuevamente.

Una cosa que podes hacer es usar la propiedad GeneratorFielddel TIBDataSet, ejemplo:
Código Delphi [-]
procedure TForm1.FormCreate(Sender: TObject);
var
  DS: TIBDataSet;
begin
  DS := IBDataSet1;
  DS.GeneratorField.Generator   := 'G_TABLA';
  DS.GeneratorField.Field       := 'ID';
  DS.GeneratorField.IncrementBy := 1;
  DS.GeneratorField.ApplyEvent  := gamOnPost;
end;
(Configuré la propiedad en tiempo de ejecución para clarificar, pero podes hacerlo en tiempo de diseño desde el Inspector Object)


Hay dos cosas que olvidé mencionarte, la primera es que los componentes IBX para Delphi hasta la versión 7.8 inclusive, no soportan la cláusula RETURNING (no sé si es así en versiónes posteriores de IBX).

La segunda y mas importante, es que no uses el modo del mensaje #7
Código SQL [-]
SELECT MAX(ID_PRODUCTO) as ULTIMO_ID FROM PRODUCTO
para obtener el último identificador en un entorno multiusuario, por que fácilmente se podría generar incongruencia en los datos. Lo conveniente es solicitar la generación de un ID
Código SQL [-]
SELECT GEN_ID(G_PRODUCTO, 1) AS TENTATIVE_ID FROM RDB$DATABASE
, almacenarlo y luego utilizarlo (Commit) o bién descartar ese valor (Rollback).

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #17  
Antiguo 01-03-2017
Avatar de anubis
anubis anubis is offline
Miembro
 
Registrado: mar 2007
Posts: 852
Poder: 11
anubis Va por buen camino
Muchas gracias eficsa,
Lo voy a checar, aunque ya me has aclarado bastante, sobretodo con la duda que llevo mucho tiempo sin resolver, que el dataset no se entera del id generado hasta que no cierre y vuelva a abrir.

Y, respecto al generador, usare tu solución , es entendible y ademas, llevo con esto mucho tiempo pero sigo siendo novato, incluso no creo que llegue a esa categoria por el tiempo .
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
forma de programar no se si es la correcta ? gulder MySQL 4 05-04-2016 17:49:51
Liberar Tlist de forma correcta BDWONG Varios 3 01-11-2014 17:28:46
Forma correcta de conectar a la base.. linuxtin Conexión con bases de datos 4 19-07-2012 20:30:20
validar usuarios de forma correcta hibero PHP 3 04-01-2010 15:47:04
Cual es la Forma Correcta de Guardar Texto en un IbDataset con TcpServer???? AGAG4 Varios 0 10-12-2004 22:14:41


La franja horaria es GMT +2. Ahora son las 05:00:39.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi