Ir al contenido


Foto

manejo de excepciones y praxis?


  • Por favor identifícate para responder
48 respuestas en este tema

#21 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 04 abril 2016 - 12:35

En el cuadro de mensaje de la excepción, saca en pantalla "registro duplicado" y "SQL Error constraint failed". Este mensaje tambien aparece cuando duplicaba un registro. Pero, el registro que inserto no está en la BB.DD,con lo cual no puede entrar por ahí, sino grabarlo.

 

Toda la documentación que puedo aprender de vosotros, la voy adaptando poco a poco en mi proyecto, cambiando y variando cosas, para poder sacar conclusiones, pero claro con pequeñas porciones de sentencias para ir asimilando que hacen y como actuan, como ocurre con las excepciones ya que a partir de que funcione, iré añandiendole nuevas sentencias para ver como se comportan.

 

 

Un saludo


  • 1

#22 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 04 abril 2016 - 01:20

Prueba a agregar esto en tu cuadro de dialogo


delphi
  1. E.ClassName

El metodo ClassName que entienden todos los objetos Delphi, devuelve una representacion string con el nombre de la clase


  • 0

#23 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 04 abril 2016 - 02:22

En el mensaje del cuadro de dialogo, ahora me indica "Registro repetido. EZSQLExcepcion"

 

A ver por que puediera ser....

 

saludos


  • 0

#24 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 abril 2016 - 03:02

El "SQL Error constraint failed" está diciendo que el error es una violación de constante. Que traducido al caso, es una violación de clave primaria. Esto da la pauta de que estás intentando insertar un mismo nombre. En el código le estás poniendo un nombre fijo, por tanto cada vez que presiones el botón va a intentar insertarlo, motivo por el cual rechaza.

 

Si dices que le cambias, lo que seguro haces es modificar el código y poner otro nombre, volver a compilar y ejecutar. Eso no es nada sano y engorroso. Para tal caso basta con que pongas dos edits y le pases el contenido de los edits a los parámetros :nombre y :edad (obviamente aplicando una conversión de texto a integer, StrToInt para este caso).

 

Si aún insistes con que da el mismo problema, mi sospecha es que antes de que alteres el código para que el campo nombre sea clave primaria tu insertaste personas. Y como ahora lo pusiste para que sea clave primaria e intentas con un nombre previamente insertado, ¡pum! detecta que ya había un registro con el mismo nombre.

 

Insisto: no es nada sano que nombre sea clave primaria. Ni siquiera para un sistema de prueba. Lo mejor es disponer de un campo artificial ID para ello.

 

Saludos,


  • 1

#25 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 04 abril 2016 - 03:15

Te entiendo Delphis perfectamente. Efectivamente Delphius eso hago al insertar un registro, a través de código. Pero debería funcionar. Por supuesto cuando consiga hacerlo funcionar, iré ampliando con un nuevo campo como puede ser su documento nacional identidad que es único para cada uno, tambien usar un dbedit para cargar datos y no como ahora hago, pero como ya he comentado no quiero "enmarañar" más el código no siendo operativo en estos momentos.

 

Para comprobar lo que comentas de tener registro previos, he eliminado la base de datos que se crea, para volver a cargar datos, pero  vaya mi sorpresa que crea de nuevo la base de datos, intento insertar el registro del código y este se niega aparecer en el DBGrid, aparece una fila como insertada, pero con sus columnas vacias. Supongo que vendrá todo de lo mismo...

 

saludos


  • 0

#26 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 04 abril 2016 - 08:07

Es que es muy sencillo, el DBGrid no esta mostrando datos porque:

 

a. No tiene DataSet asociado

b. El DataSet que tiene asociado esta cerrado

c. El DataSet que tiene asociado esta vacio

d. El DataSet que tiene asociado "no es quien crees que es"

 

No puede haber otra explicacion (ok, esta lo del DefaultDrawing pero creo que eso ya lo aprendiste :D)

 

Estas cosas son super facil de depurar chequeando las propiedades mas triviales

 

** En general en la jerga, por brevedad, cuando hablamos del "DataSet del Grid" estamos haciendo referencia al DataSet que esta en la propiedad DataSource del DBGrid

 

Como se depura lo anterior? Facil, para:

 

a y d. Coloca una linea de codigo que haga "algo" con el DataSet luego de insertar, o bien en un boton provisorio. Haz que se ejecute algun codigo simplon como ShowMessage(DBGrid1.DataSource.DataSet.Name)

 

Si la instruccion falla con una excepcion EAcessViolation quiere decir que "No tiene DataSet asociado"

Si la instruccion se ejecuta correctamente te deberia salir en pantalla ZQuery1 o ZQuery2. De este modo te das cuenta si es el DataSet que realiza la instruccion select from personas

 

b. Dispones de la propiedad Booleana Active. Basicamente si DataSet.Active = True, esta abierto y deberias ver datos, si es False esta cerrado y por eso no lo ves

 

c. Hay 2 formas de comprobarlo: Propiedad Booleana IsEmpty y propiedad Integer RecordCount. Si IsEmpty evalua a True, esta vacio y es logico que no veas datos; lo mismo si RecordCount = 0 

 

El que aprendas a depurar tu codigo es absolutamente imprescindible

 

Un error muy pero muy error que cometen los novatos (y no tan novatos) es no entender que las objetos son un tipo especial de variables,un apuntador a una zona de memoria

 

Una cosa es decir que la variable A := B donde A y B son Integer, o string (busca y lee sobre tipos primitivos). En ese caso esa asignacion produce una copia

 

Pero tal y como te explico Delphius, con objetos no estas copiando nada

 

Poniendolo en palabras simples, sean ZQuery1 y ZQuery2 dos variables de tipo TZQuery:


delphi
  1. // en este punto supongamos que ZQuery1 y ZQuery2 estan los dos en su modulo de datos y apenas arranco el programa...
  2.  
  3. var
  4. q: TZQuery;
  5. // esta sentencia evalua a False
  6. if ZQuery1 = ZQuery2 then
  7.  
  8. // ZQuery1 esta enlazado a DBGrid1
  9. ZQuery1.SQL.Text := 'SELECT * FROM Personas';
  10. ZQuery1.Open;
  11.  
  12. ZQuery2 := ZQuery1;
  13. // apenas se ejecuta la instruccion anterior, perdiste y no podes volver a recuperar (facilmente al menos) a ZQuery2
  14. // ahora ZQuery1 y ZQuery2 "son la misma cosa". Son sinonimos, son el mismo apuntador que apunta a la misma zona de memoria
  15.  
  16.  
  17. q := ZQuery1;
  18.  
  19. q.Close; // para tu sorpresa, en el DBGrid en este punto no vas a ver datos..
  20.  
  21. // todas estas evaluan a False! cerraste "los 3 query" (en realidad es uno solo)
  22. ZQuery1.Active = False
  23. ZQuery2.Active = False
  24. q.Active = False
  25.  
  26. // lo podes comprobar facilmente imprimiendo la propiedad Name como mas arriba


  • 1

#27 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6.295 mensajes
  • LocationArgentina

Escrito 04 abril 2016 - 09:10

Es necesario dooper que evoluciones tu metodología tanto al programar como al exponer tus dudas:

1. Cuando copies código, indica a que pertenece. Muchas veces nos dices algo como "esto es lo que hace el botón" y pones código suelto. No sabemos si efectivamente hay algo antes, ni después. No es lo mismo ver algo como esto:


delphi
  1. for i := 0 to Lista.Count - 1 do
  2. Memo1.Lines.Add(Lista[i]);

Que ver esto:


delphi
  1. procedure TForm1.Button1Click(Sender: TObject)
  2. var i: integer;
  3. begin
  4. for i := 0 to Lista.Count - 1 do
  5. Memo1.Lines.Add(Lista[i]);
  6. end;

En la primera muestra no se tiene la seguridad si se hace algo antes esas líneas, ni después. En el 2do código vemos donde empieza, donde termina, las variables, el evento, su implementación completa.

 

2. Separa tu código. No pongas todo el código de una (a menos claro que se vea toda la unit claro) Separa los tantos. Por ejemplo. Si dices "esto tengo en el botón de Agregar", limitate a poner todo el código del botón agregar.

Si quieres exponer más código, menciona a que hace referencia. Usa las etiquetas de código sabiamente:

 

Bla, bla, bla:

[codigo etiquetado]

 

Más explicaciones por aquí

[más código etiquetado]

 

Eso es mucho más claro que nos pongas código de diferentes cosas en un mismo etiquetado. Que es lo que haces tu, y hace difícil entender la idea.

 

3. Ponle nombres adecuados a tus variables y componentes. Nosotros en los ejemplos ponemos Query1, QueryPersonas, o cosas por el estilo. Tu dales el nombre más adecuado. Esto ayuda mucho a etender las cosas, y lo que se pretende hacer. Por ejemplo es mucho más claro leer QueryInsertarPersona que un Query1, ni que decir si por ejemplo detectamos que al QueryInsertarPersona en realidad lo usas para un SELECT.

 

4. Cuando te aparezca error, copia el texto con Ctrl + C y pégalo. También comenta en que línea de código da el problema. Elimina de tu vocabulario la expresión "salta". En su lugar di: "Se levanta el error o excepción de la clase tal con el texto tal". El propio mensaje de la excepción menciona la clase de excepción y el texto descriptivo. Además cuando el programa se detiene por una excepción el propio IDE cuando cierras el mensaje te lleva a la línea problemática. Haznosla saber comentando en el código que nos muestre así:


delphi
  1. // error aquí! <----

5. El ShowMessage() puede ser buen aliado durante el tiempo de desarrollo. Interrumpir parcialmente el código con "leyendas" como "Ejecutando botón insertar", "Todo listo" y acompañado de evaluaciones como:


delphi
  1. // Hacer algo con un Query
  2. if Query.Active
  3. then ShowMessage('Ummm. Ya trabajé con el Query y ahora debería estar cerrado')
  4. else ShowMessage('Perfecto. Ya está cerrado');
  5. // para llegar a este punto deberíamos tener garantizado el query cerrado. Si se ejecutó
  6. // la parte then le ha faltado hacer un close o un Active := false.

Este tipo de programación básica con "código relleno" de prueba es nuestro primer depurador para detectar si algo va bien o mal. Es una buena forma de llevar registro de como se van haciendo las cosas.

 

6. Programa a la defensiva. Diseña tus "demos" de prueba de concepto y cuando tengas las cosas ya probadas, lleva ese código al sistema real. Yo tengo organizado mis proyectos así: en el directorio donde tengo el proyecto creo una subcarpeta que diga Pruebas. Y en ella voy armando tantas subcarpetas como pruebas a mis unidades tenga y necesite. Si bien parece más engorroso ya que terminas generando muchos proyectos, es mucho más limpio. Ya no estás copiando, pegando, borrando y agregando código cientos de veces en tu propio sistema. Deja esa "basura" en "prototipos desechables" y el código ya limpio y probado va directo al sistema y reduces los problemas a largo plazo.

 

Con eso ya tienes para empezar. Hay más tips, pero eso será para cuando estés más adelante.

 

Y pon en práctica lo que ha comentado Agustín. Que seguro que tu problema está en alguna de esas 4 posibilidades. ;)

 

Saludos,


  • 1

#28 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 05 abril 2016 - 06:26

Agregando a las sugerencias de delphius, puedes resaltar la linea donde marca error poniéndole ## delante, la etiqueta resalta la linea automáticamente con un color amarillo.

Saludos.

Enviado desde mi SPH-L720 mediante Tapatalk
  • 0

#29 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 05 abril 2016 - 11:32

Quiero adelantar que os estoy enormemente agradecido por vuestro tiempo y ayuda en todo momento. Eso que vaya por delante.
Todo lo que aprendí y es poco, es por vuestra total dedicación por un principiante que se embarcó en programar en un entorno visual con muchas ganas y tesón y que sin gente valiosa como este foro, muchos y yo mi incluyo, el nivel de apredizaje hubiera sido mucho más lento y en otros cosas la total desmotivación y dejadez en el mismo.
 
Pasando al problema, quizás las preguntas de un principiante sean para algunos de vosotros triviales y simples en su problemática y solución, pero dar con ellas para muchos como yo, es un gran paso para poder abarcar otros nuevos retos en el código. Le dedico muchas horas, dentro de mis huecos, pero hay "atascos" que por muchas vueltas y horas que te enfrentes a ellos, uno termina sin esperanza de salir adelante.
 
Nunca llegué a pensar que introducirme en el mundo de la "DB(Grid),DB(Edit)....." fuera tan abstracto y arduo para mí, pero ahora sé que muchos conocimientos han cambiado un poco para enfrentarme a ellos.
 
Razón llevas Delphius, intento acotar las preguntas para no ser tan extenso, pero es cierto que muchas veces no expongo bien mi duda, porque al leer después me doy cuenta.
Agustín expone una amplia gama de teorias y conocimientos a pautar. Todo los recojo en un pequeño cuarderno y los estudio como otros de Delphius, enecumene, etc... pero hay veces que mis limitados conocimientos no los entienden en su totalidad, por ello permitirme si soy repetitivo o si el problema lo expongo desde varios ámbitos, pero se irán refinando según vaya adquiriendo tablas en la materia.
 
Veamos! El problema está en que siempre saca registro repetido, aunque en el propio codigo cambie contenido de la variable "nombre".

delphi
  1. procedure TForm1.ToolButton1Click(Sender: TObject); //Boton MOSTRAR GRILLA.
  2. begin
  3. Form2:= TForm2.create(self);
  4. Form2.parent := Panel1;
  5. Form2.show;
  6.  
  7. DataModule1.ZQuery1.Close; //Por si acaso Zquery1 usado para lectura del DBGrid.
  8. DataModule1.ZQuery1.SQL.Text := 'CREATE TABLE IF NOT EXISTS "personas" ("nombre" varchar(10) PRIMARY KEY, "edad" INTEGER)';
  9. DataModule1.ZQuery1.ExecSQL;
  10.  
  11. Try
  12. //Cerramos la tabla
  13. DataModule1.ZQuery1.close;
  14. DataModule1.ZQuery1.SQL.Text:= 'SELECT * FROM "personas"';
  15. DataModule1.ZQuery1.Open;
  16.  
  17. except
  18. on E:Exception do
  19. begin
  20. ShowMessage('El error provocado en volcado lectura DBGRID ha sido: '+E.Message); //E.ClassName
  21. //Datamodule1.Zconnection1.RollBack;
  22. end;
  23. end; //end-Try
  24. end;
  25.  
  26.  
  27. // Procedimiento para insertar un nuevo registro en tabla. Creado un Zquery2 en datamodule1 para
  28. // insertarlo con la misma configuracion que Zquery1.
  29.  
  30. procedure TForm2.ToolButton1Click(Sender: TObject);(Sender: TObject); // BOTON ICONO "NUEVO"
  31. begin
  32. //Datamodule1.ZQuery1.Close; // Si activo el DBGrid deja de mostrar, por lo tanto dejo abierto
  33. DataModule1.ZQuery2.SQL.Text := 'INSERT INTO "personas" (nombre, edad) VALUES (:nombre, :edad)';
  34. // Con la grilla en pantalla visualizando todo la tabla, intento insertar un nuevo registro "Marianito y 89"
  35. // pero siempre entra por la except mostrando "nombre está duplicado" cuando este nombre no está
  36. // en la base de datos.
  37. Try
  38. Datamodule1.ZQuery2.ParamByName('nombre').AsString:='Marianito';
  39. Datamodule1.ZQuery2.ParamByName('edad').AsInteger=89;
  40. DataModule1.ZQuery2.ExecSQL;
  41.  
  42. except
  43. on E:Exception do
  44. begin
  45. ShowMessage('El nombre está duplicado!: '+E.ClassName);
  46. // Datamodule1.Zconnection1.RollBack;
  47. end;
  48. end;

Un saludo
  • 0

#30 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 05 abril 2016 - 12:43

Es que no has cambiado en nada el codigo

 

No has entendido correctamente excepciones

 

Crea una nueva aplicacion, pon un boton y colocale este codigo en el OnClick y veras lo que sucede:


delphi
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3. Cero: Integer;
  4. begin
  5. try
  6. Cero := 0;
  7. ShowMessage(FloatToStr(20 div Cero));
  8. except
  9. ShowMessage('El registro esta duplicado ');
  10. end;
  11. end;


Editado por Agustin Ortu, 05 abril 2016 - 12:44 .

  • 0

#31 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 05 abril 2016 - 01:23

Pues sigo sin entenderlo Agustin. He visto tu codigo, al ejecutarlo me da error "el project1 ha lanzado una excepcion de la clase external SIGFPE". Entiendo que es provocado por una division por 0. Pero sinceramente, se que algo me falla mentalmente. 

 

Veamos, desde mi punto de vista Divide por 0 dentro de Try, pero como no es posible da un error, pero para que está entonces Except, si en ningun momento entra por esa vía?

Mi mente entiende lo siguiente: Dentro del Try poner las instrucciones necesarias (abrir ,leer, etc...) si da error el flujo de codigo pasa al 

except dando aviso del error generado.

 

Por eso en mi codigo lo veo desde ese punto de vista


php
  1. Try
  2. // Haz esto... es decir inserta un registro
  3. Datamodule1.Zquery2.SQL.Text:= 'INSERT TO INTO "personas" (nombre, edad) VALUES (:nombre, :edad)';
  4. Datamodule1.ZQuery2.ParamByName('nombre').AsString:='Marianito';
  5. Datamodule1.ZQuery2.ParamByName('edad').AsInteger=89;
  6. DataModule1.ZQuery2.ExecSQL;
  7.  
  8. except // si me das error en la inserción captura dicho error en funcion de cual sea.
  9. on E:Exception do // cierto es que captura todos genericamente
  10. begin
  11. ShowMessage('El nombre está duplicado!: '+E.ClassName); //muestra error

:(


  • 0

#32 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 05 abril 2016 - 01:57

Primero que nada olvidate del programa de las bases de datos; añade un nivel adicional de complejidad ya que estas intentando entender 2 conceptos al mismo tiempo. Escribe codigo sencillo para aprender las cosas, ya luego cuando tengas que unir partes veras como aplicar y juntar todo lo aprendido

 

 

Claro el "problema" es que estas ejecutando desde el depurador

 

Cuando se ejecuta sin el depurador, directamente se ejecuta el codigo del except

 

No he encontrado en Lazarus (y me imagino que CodeTyphon es igual) la opcion "Run without debugging"

 

Cuando ejecutas usando el depurado integrado, este se "engancha" a tu aplicacion. Cuando se produce una excepcion, el la "atrapa" y te muestra un cartel con la excepcion en cuestion, y te permite ir a la linea de codigo en ese momento o continuar

 

Si pones continuar, el comportamiento es distinto dependiende de: Estoy dentro de un bloque try o no (no importa si es except o finally)

 

1. El caso mas sencillo, no estoy en un bloque try


delphi
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3. Cero: Integer;
  4. begin
  5. Cero := 0;
  6. ShowMessage(FloatToStr(20 div Cero));
  7. end;

En este simple codigo de 2 lineas, podemos dividirlo en pequeñas sentencias mas simples:

 

a. Guardar el valor 0 en la variable "Cero"

b. Realizar la cuenta 20 dividido valor de la variable "Cero"

c. Convertir a string el resultado de b

d. Mostrar en un dialogo el resultado de c

 

No hay try, por lo tanto el codigo apenas ocurre la excepcion, todo lo que "faltaba por hacer", es decir, todo lo que este debajo del punto en el cual se elevo la excepcion, nunca se ejecuta: se interrumpe la ejecucion, se muestra un mensaje de error, y se "sale" del metodo en cuestion

 

2. Caso try-except, vuelvo a copiar el codigo de mas arriba


delphi
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3. Cero: Integer;
  4. begin
  5. try
  6. Cero := 0;
  7. ShowMessage(FloatToStr(20 div Cero));
  8. except
  9. ShowMessage('El registro esta duplicado ');
  10. end;
  11. end;

En este caso podria decirse que, en esencia son los mismos 4 elementos de arriba, pero imaginate que estan entre parentesis, asi

 

try

(

a. Guardar el valor 0 en la variable "Cero"

b. Realizar la cuenta 20 dividido valor de la variable "Cero"

c. Convertir a string el resultado de b

d. Mostrar en un dialogo el resultado de c

)

except

 

Dentro del parentesis, el codigo se comporta igual. Si hay un error, se detiene la ejecucion en esa linea, se eleva la excepcion pero en este caso es capturada por el bloque del except. Es decir, el error esta, pero el programador decide hacerse cargo de el, porque esta a la espera de potenciales errores. Como la excepcion es capturada para que el programador se haga cargo, el mensaje de error "en chino mandarin y los numeros raros" no se muestra, ya que se le permite al programador "personalizar el comportamiento del programa"

 

Por que te hice escribir ese codigo tan bobo? Porque basicamente produce una excepcion adrede y muestra un cartel en pantalla diciendo "El registro esta duplicado". Que registro. Si nunca intente insertar nada. Si no hay base de datos ni query ni nada. 

 

Esto lo recalco porque en tus mensajes insistis con "siempre me sale que el registro esta duplicado". No. No sabemos cual es el problema. Sabemos que es una excepcion de base de datos porque cuando te dije que imprimas el nombre de la clase de la exception dio "EZSQLExcepcion". Y simplemente quiere decir eso: Es una excepcion "generica" de base de datos.

 

Ahora, obviamente confunde el hecho de que aparezca un cartel que diga: "Registro duplicado. EZSQLExcepcion". Pero eso es culpa del programador que basicamente escribio este codigo, traducido en poseia

 

"Inserta el registro con nombre: marianito y edad: 89. Si hay algun problema imprime en pantalla que es un registro duplicado. No importa si la computadora se quedo sin memoria, si la base de datos no existe, si la tabla no existe, si hay un error en el tipo de datos, si hay un error de memoria corrupta, si fallo el disco rigido, o si el usuario no dispone de permisos escritura. Tu solo pon en pantalla para todos los casos que el registro esta duplicado"

 

Eso es literalmente lo que dice tu codigo. Estas disfrazando todos los problemas con "el registro esta duplicado". Y hay infinidad de excepciones que pueden ocurrir, alguna de las cuales ni se nos pasan por la cabeza en este momento

 

3. Caso try-finally

 

Una pequeña variacion del codigo anterior:


delphi
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3. Cero: Integer;
  4. begin
  5. try
  6. Cero := 0;
  7. ShowMessage(FloatToStr(20 div Cero));
  8. finally
  9. ShowMessage('El finally siempre se ejecuta');
  10. end;
  11. end; 

El finally es una estructura bastante curiosa: siempre se ejeucta. Siempre recibe el flujo de ejecucion. Lo cual no quiere decir que se garantiza que el finally se ejecuta desde la primera hasta la ultima instruccion

 

En un finally basicamente colocamos codigo que queremos que se ejecute siempre: ocurran errores o no. De hecho cuando mas adelante estudies estructuras de control iterativas, veras que si dentro de un try finally pones un Break, un Continue o un Exit, el finally se ejecuta siempre

 

En el codigo anterior, veras una excepcion en el momento que se divide por 0, tal y como ya venia pasando. La diferencia es, que una vez que se muestra la excepcion (pones aceptar) la siguiente instruccion es "ejecuta el finally"

 

Si no pongo el try-finally, el cuadro que imprime "El finally siempre se ejecuta", ironicamente, es una instruccion que nunca se va a ejecutar

 


  • 0

#33 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 05 abril 2016 - 02:13

Por otra parte:


delphi
  1. procedure TForm2.ToolButton1Click(Sender: TObject);(Sender: TObject); // BOTON ICONO "NUEVO"
  2. begin
  3. //Datamodule1.ZQuery1.Close; // Si activo el DBGrid deja de mostrar, por lo tanto dejo abierto

Close es cerrado. Si pones a Close un Query, el DBGrid se va a quedar sin nada que mostrar. El comentario que acompaña ahi es incorrecto y puede prestar a confusion.

 

 

El metodo correcto para insertar un nuevo registro, y que luego despues puedas verlo en la pantalla es el siguiente:


delphi
  1. // 1 preparacion del query
  2. qInsertaPersona.SQL.Text := ' INSERT INTO "personas" (nombre, edad) VALUES (:nombre, :edad) ';
  3.  
  4. // 2 colocar los parametros
  5. qInsertaPersona.ParamByName('Nombre').AsString := 'Marianito';
  6. qInsertaPersona.ParamByName('Edad').AsInteger := 89;
  7.  
  8. // 3 ejecucion del query. Notar que todavia no inclui el try-except. Si la computadora se queda sin memoria o hay un error de disco
  9. // es preferible que Lazarus se haga cargo de ello y muestre el verdadero problema. En esas 3 lineas de codigo no existe un solo caso en el que
  10. // pueda ocurrir una excepcion en la que el "problema" sea un registro duplicado: Todavia no intente insertar!
  11.  
  12. try
  13. qInsertaPersona.ExecSQL;
  14. except
  15. on E: ENombreDeLaClaseQueZeosUsaParaRegistrosDuplicados do
  16. begin
  17. ShowMessage('Registro duplicado')
  18. end;
  19.  
  20. // si no es esa excepcion, por favor, muestra el error real en pantalla
  21. else
  22. raise E;
  23. end;
  24.  
  25. // si llegamos hasta aca, el registro fue insertado. Tiene sentido realizar un refresco en los datos del grid
  26. qListaPersonas.Close; // cerramos..
  27. qListaPersonas.Open; // y abrimos. Es como volver a ejecutar

Si no hay una excepcion que Zeos haya definido para los registros duplicados, tendras que evaluar como te dijo enecumene mas arriba por el codigo de error


  • 1

#34 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 06 abril 2016 - 10:58

Quizás no entienda porque me sucede esto, aunque intento analizar vuestra sugerencias. 

El caso es que siempre  al insertar un registro me dice una y otra vez que el "nombre" ya está duplicado ya que el código que me indica  "SQL Error Constraint failed" es por ese motivo pero en realidad ese registro no está insertado en la tabla. Lo compruebo abriendo la bb.dd y asi es.

 

Porque se va el flujo por esa opción de except, cuando tendría que insertarlo? He cambiado a la opcion que indicas Agustin en el código anterior y nada!

 

La lectura completa del DBgrid cuando pulso un botón es correcta, al pulsar el siguiente boton "nuevo" para insertar el registro no hay manera humana de discernir un nuevo "nombre".

 

Un saludo


  • 0

#35 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 06 abril 2016 - 11:51

Osea que estamos diciendo que en el archivo donde esta la base de datos hay una cosa y en el programa otra?

 

Si no intentas insertar nada, y ejecutas el boton que lista en el dbgrid, la tabla esta vacia?


  • 0

#36 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 06 abril 2016 - 02:35

No, lo que ocurre, es que en el fichero bb.dd aparecen los registros que iba insertando. Hasta ahora lo que hacía era pulsar boton personas, y visualiza el contenido de la tabla en un dbgrid e insertaba al mismo tiempo. Ahí aparecen los que tengo insertados, pero porque están insertados? pues porque antes el codigo estaba todo en un mismo procedimiento (visualizar, insertar) y funcionaba pero lo hacía con nombres repetidos. Ahora lo que hago es el boton "personas" visualizo, y un boton "nuevo" inserto, y es en este procedimiento insertar cuando siempre inserte por codigo un nombre no repetido, me indica clave repetida, con lo cual la base de datos o mejor tabla personas ya no inserta nombres en ningun momento. Abro la tabla y nada.

 

Es más elimino la bb.dd de la carpeta del proyecto y elimino del CREATE.... la palabra PRIMARY KEY y al ejecutar el programa. Visualizo, pero no aparecen registros, es normal ya que hasta que no pulse boton "nuevo" no insertará el nombre que le indico por código, pero, intento insertar con boton "nuevo" y nada no se bloquea, pero no inserta nada. Voy al fichero de la bb.dd y se crea

pero no hay registro.

 

Algo tiene que ser al crear un ZQuery2 para la inserción, o quizás algo que no haya tenido en cuenta a la hora de cambiar y tener

ahora un procedure para insertar y otro para leer dbgrid.

 

un saludo


  • 0

#37 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 07 abril 2016 - 12:57

Bueno, pues ya he dado con el tema, despus de horas y horas dedicado a ver que solución darle...

 

Inserté un nuevo Zquery2 para insertar, y el Zquery1 para visualizar el DbGrid. Pero en el Zquery1 está puesto en DataSource-> Form2.DataSource1.

 

En el caso del Zquery2 lo he dejado vacío el DataSource, cuando antes tambien lo puse a Form2.DataSource1 como el ZQuery1 y ha funcionado a la primera, inserta cuando no es clave repetida, y avisa cuando es clave repetida. No se porque debo dejarlo vacío y en el Zquery1 está a Form2.DataSource1.

 

Pasos a seguir ahora, siguiendo vuestros importantes consejos

 

- Terminar de ver las excepciones porque no se porque EZSQLException y ErrorCode no me los reconoce por lo tanto, el codigo de enecumene de

no me termina de compilar.


php
  1. except
  2. on E:EDataBaseError do
  3. case EZSQLException(E).ErrorCode of
  4. 1: '......'
  5. 2: '......'
  6. end;

- Insertar datos con un DbEdit, en vez de insertar en codigo.

- Usar el finally para ver como funciona, ya que despues de isertar debo visualizar el dbgrid con el nuevo registro y debo volver a "barrer" con un select.

- Borrar registros y modificar.

 

Vamos avanzando despacio, pero volviendo a coger motivación.... y con nuevo conceptos y conocimiento a cuesta!

 

Gracias compañeros!

 

Un saludo


  • 0

#38 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 07 abril 2016 - 01:23

Una sugerencia, en la parte donde creas la base de datos colócalo en la creación del datamodule y la inserción en el botón, es mejor separar ambas cosas.


Enviado desde mi SPH-L720 mediante Tapatalk
  • 0

#39 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 07 abril 2016 - 02:10

Primero pegate un martillazo en la cabeza cada vez que leas que un componente tiene el nombre por defecto. Label1, Edit1, ZQuery1..mas aun cuando ese componente lo vas a usar para algo especifico, en el caso de un TLabel que le pones el texto en tiempo de diseño y luego te olvidas es aceptable
 
Pero ya me estoy mareando de quien es cada cosa y eso que apenas son dos query
 
Dales un nombre

 

Segundo

 

 

Inserté un nuevo Zquery2 para insertar, y el Zquery1 para visualizar el DbGrid. Pero en el Zquery1 está puesto en DataSource-> Form2.DataSource1.

 
Eso esta al revez
 
En el Form donde pones el Grid, tenes un componente DataSource. Le vamos a llamar dsGridPersonas. En ese dsGridPersonas, hay una propiedad DataSet. En esa propiedad DataSet vamos a poner a qryListaPersonas. qryListaPersonas es el ZQuery que ejecuta la sentencia SQL SELECT * FROM Personas
 
Luego renombra el ZQuery2 y ponle qryInsertaPersona o algo similar

  • 0

#40 dooper

dooper

    Advanced Member

  • Miembros
  • PipPipPip
  • 298 mensajes

Escrito 07 abril 2016 - 03:58

Una sugerencia, en la parte donde creas la base de datos colócalo en la creación del datamodule y la inserción en el botón, es mejor separar ambas cosas.


Enviado desde mi SPH-L720 mediante Tapatalk

 

Perfecto enecumene tu sugerencia.


  • 0




IP.Board spam blocked by CleanTalk.