Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   MySQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=21)
-   -   Problemas con Firedac y mysql (https://www.clubdelphi.com/foros/showthread.php?t=93443)

JoAnCa 28-09-2018 17:44:56

Problemas con Firedac y mysql
 
1 Archivos Adjunto(s)
Hola a todos
Tengo una aplicación que debe calcular los datos de una prenomina, basandose en otros campos de otras tablas.
Pero en algunos casos me da el error q muestro en la imagen adjunta

La logica del formulario es:
- Seleccionar el area de trabajo y se filtran los datagrid (2 datagrid)
- Clic en boton Calcular y hace los cálculos de las prenominas de cada datagrid

Depurando veo que el error lo da cuando hago el post para guardar el registro

Que podra estar pasando?

El error sale solo en un area, al guardar determinado trabajador, en las otras hace los calulos bien.

Pensando en problemas con ese trabajador, lo elimino, y el error lo da en otro cualquiera


Los datagrid los baso en una consulta de mysql, que es editable

Casimiro Notevi 28-09-2018 19:11:37

Bueno, ahí da una explicación de lo que puede estar pasando. Poco más podemos hacer con la no información que das, sin ver código ni tener nada con lo que hacer pruebas.

JoAnCa 28-09-2018 19:27:01

Quizas la logica que uso no sea la mas adecuada, por lo que cualquier sugerencia para cambiarla sera aceptada.

El problema es que tengo una tabla prenominas, pero al calcular tengo que dividirla en dos, los miembros de la direccion y los consultores.
Entonces hago dos consultas basadas en prenomina, una para la direccion del area y otra para los consultores de esa area, y los muestro en sus datagrid respectivos.

Al calcular, las formulas de los 2 casos son diferentes, pero la cantidad de salario a distribuir es comun para los dos.

En una ocasion el error me lo dio en la consulta de la direccion de la 2da area, vacie la tabla y despues me lo da en la consulta de los consultores en la 6ta area.

Es decir, que da el error arbitrariamente ??

Este es el codigo que uso en el boton Calcular
Código Delphi [-]
  with ModuloBD do
  begin
    //--- Direccion del Grupo de Trabajo ---
    TDeveng:=0; TAjust:=0; TPenal:=0;
    fdtPrenomGTDir.First;
    fdtPrenomGTDir.DisableControls;
    while not fdtPrenomGTDir.Eof do
    begin
      fdtPrenomGTDir.Edit;
        fdtPrenomGTDirSalarioNeto.Value:=fdtPrenomGTDirSalarioAjust.Value + fdtPrenomGTDirEstimAdic.Value;
        fdtPrenomGTDirEstimulac.Value:=fdtPrenomGTDirSalarioNeto.Value - fdtPrenomGTDirSalarioDeveng.Value;
        // Calcular el formado
        if fdtPrenomGTDirIngresos.Value > 0 then
          SalForm:=fdtPrenomGTDirIngresos.Value * fdtAuxiliarCDSEspPrinc.Value
        else
        begin
          //--- Si es el Esp. Princiapal ---
          if fdtPrenomGTDirIDSUBCAT.Value = 7 then
            if frmSisleg.CantTrabGT > 0 then SalForm:=(fdtIngxGruposMontoADist.Value / frmSisleg.CantTrabGT) * fdtPrenomGTDirSalarioDeveng.Value / fdtPrenomGTDirSalarioBasico.Value
            else SalForm:=0
          //--- Si es la Contadora
          else
            if frmSisleg.CantTrabGT > 0 then SalForm:=(fdtIngxGruposMontoADist.Value / frmSisleg.CantTrabGT) * fdtPrenomGTDirSalarioDeveng.Value / fdtPrenomGTDirSalarioBasico.Value * 50 / 100
            else SalForm:=0
        end;
        fdtPrenomGTDirSalarioFormado.Value:=SalForm;
      fdtPrenomGTDir.Post;
      //--- Totalizar ---
      TAjust:=TAjust + fdtPrenomGTDirSalarioAjust.Value;
      TPenal:=TPenal + fdtPrenomGTDirPenalizacion.Value;
      fdtPrenomGTDir.Next;
    end;
    fdtPrenomGTDir.First;   fdtPrenomGTDir.Refresh;
    fdtPrenomGTDir.EnableControls;
    qryTotPrenomGTDir.Refresh;
    TDeveng:=dbtxtTotSalEsc.Field.Value + dbtxtTotDFer.Field.Value + dbtxtTotOtrosP.Field.Value;
    lblDevengDG.Caption:=FloatToStrF(TDeveng, ffNumber, 6, 2);
    lblSalAjustDG.Caption:=FloatToStrF(TAjust, ffNumber, 6, 2);
    lblTotPenalDG.Caption:=FloatToStrF(TPenal, ffNumber, 6, 2);

    //--- Consultores ---
    fdtPrenomGTCons.Refresh;
    TDeveng:=0; TAjust:=0; TPenal:=0;
    fdtPrenomGTCons.DisableControls;
    fdtPrenomGTCons.First;
    while not fdtPrenomGTCons.Eof do
    begin
      fdtPrenomGTCons.Edit;
        fdtPrenomGTConsSalarioNeto.Value:=fdtPrenomGTConsSalarioAjust.Value + fdtPrenomGTConsEstimAdic.Value;
        fdtPrenomGTConsEstimulac.Value:=fdtPrenomGTConsSalarioNeto.Value - fdtPrenomGTConsSalarioDeveng.Value;
        // Calcular el formado
        if fdtPrenomGTConsIngresos.Value > 0 then
          SalForm:=fdtPrenomGTConsIngresos.Value * StrToFloatDef(lblCDSCons.Caption, 0)
        else
          SalForm:=0;
        fdtPrenomGTConsSalarioFormado.Value:=SalForm;
      fdtPrenomGTCons.Post;
      //--- Totalizar ---
      TAjust:=TAjust + fdtPrenomGTConsSalarioAjust.Value;
      TPenal:=TPenal + fdtPrenomGTConsPenalizacion.Value;
      fdtPrenomGTCons.Next;
    end;
    fdtPrenomGTCons.First;  fdtPrenomGTCons.Refresh;
    fdtPrenomGTCons.EnableControls;
    qryTotPrenomGTCons.Refresh;
    TDeveng:=dbtxtTotSalEsc1.Field.Value + dbtxtTotDFer1.Field.Value + dbtxtTotOtrosP1.Field.Value;
    lblDevengCons.Caption:=FloatToStrF(TDeveng, ffNumber, 6, 2);
    lblSalAjustCons.Caption:=FloatToStrF(TAjust, ffNumber, 6, 2);
    lblTotPenalCons.Caption:=FloatToStrF(TPenal, ffNumber, 6, 2);
  end;

Casimiro Notevi 28-09-2018 19:54:19

Lo primero que llama la atención es justo la primera línea del código:
Código Delphi [-]
with ModuloBD do
No es que esté mal ni que sea la culpable, pero ¿puedes estar seguro al 100% que todo lo que se ejecuta después no interfiere con eso?
with es un peligro, y cuanto más código involucrado, más peligro es.
Para empezar, yo eliminaría ese with. Es una fuente de problemas.
Y eso sin tan siquiera haber leído lo que hay después.

JoAnCa 28-09-2018 20:11:30

Cita:

Empezado por Casimiro Notevi (Mensaje 528683)
Lo primero que llama la atención es justo la primera línea del código:
Código Delphi [-]with ModuloBD do

No es que esté mal ni que sea la culpable, pero ¿puedes estar seguro al 100% que todo lo que se ejecuta después no interfiere con eso?
with es un peligro, y cuanto más código involucrado, más peligro es.
Para empezar, yo eliminaría ese with. Es una fuente de problemas.
Y eso sin tan siquiera haber leído lo que hay después.


Ok, lo elimine por si acaso.


Pero curiosamente, antes el error me lo daba en el 2do datagrid, ahora lo da en el primero
Por eso es que me tiene loco y no se ya donde buscar, ni que cambiar, unas veces lo da en un lugar otras en otro :confused:

Casimiro Notevi 28-09-2018 20:34:36

Tampoco entiendo lo que dices sobre que el problema lo da el "datagrid". Un dbgrid es una "ventana" que muestra los datos de un dataset, mediante un datasource que hace de intermediario.
Las consultas, cálculos, y todo lo que quieras hacer con los datos es en el dataset. El dbgrid es solamente una presentación de esos datos devueltos.
No puede haber un problema en el datagrid.

JoAnCa 28-09-2018 20:43:09

Cita:

Empezado por Casimiro Notevi (Mensaje 528685)
Tampoco entiendo lo que dices sobre que el problema lo da el "datagrid". Un dbgrid es una "ventana" que muestra los datos de un dataset, mediante un datasource que hace de intermediario.
Las consultas, cálculos, y todo lo que quieras hacer con los datos es en el dataset. El dbgrid es solamente una presentación de esos datos devueltos.
No puede haber un problema en el datagrid.


No le hecho la culpa al datagrid, en realidad quise decir en el dataset

Casimiro Notevi 28-09-2018 21:05:49

Cita:

Empezado por JoAnCa (Mensaje 528686)
No le hecho la culpa al datagrid, en realidad quise decir en el dataset

Bueno, es lo que has dicho, y nosotros solamente podemos guiarnos de lo que dices tú y todos los que plantean sus dudas. Ojalá pudiésemos conectar a tu ordenador y ayudar a buscar el problema.

JoAnCa 28-09-2018 21:55:33

Al parecer el código está bien, pues funciona bien en la mayoria de los casos


Todo me parece indicar que es como si algun registro se quedara "colgado" o en uso y por eso no deja guardarlo con los nuevos valores


Los dos datatables que uso: fdtPrenomGTDir y fdtPrenomGTCons se basan en la misma vista de MySQL, la diferencia está en el filtro que uso para cada uno, para separar la direccion del grupo de los consultores


La vista en mysql la conformo con la relacion de las tablas prenomina y trabajadores, para que me muestre el nombre del trabajador en el datagrid, en lugar de su ID


Como hago los calculos, se puede ver en el codigo que publiqué


Podria ser que el error esté en la forma que lo estoy haciendo?


Alguna idea de otra forma de hacerlo?

Casimiro Notevi 28-09-2018 22:01:10

A ver, es que no tenemos información para poder ayudarte fácilmente.
Hay cosas que tenemos que preguntar, aunque sean obvias, porque no lo has confirmado, por ejemplo, dice el mensaje de error que es posible que la tabla no tenga una primary key, ¿es así?

JoAnCa 29-09-2018 03:22:54

Pues eso es lo desconcertante del error, de las posibles causas que da, no veo que sea esa :rolleyes:
La tabla si tiene clave primaria, y tambien se las paso a las consultas, así que no debe ser por ausencia de llave primaria

Casimiro Notevi 29-09-2018 09:58:27

¿Y qué es fdtPrenomGTDir?

orodriguezca 29-09-2018 17:38:47

En mi experiencia, las veces que he tenido ese error, es porque FireDac no tiene la información suficiente o correcta para actualizar la información de los registros de la base de datos, esto es, FireDac trata de hacer un update sobre un registro pero el registro, según FirecDac, ya no existe. Cosas para revisar en estos casos:

1. Si la tabla tiene llave primaría verificar si en un FDQuery o FDTable está correctamente asignada la propiedad UpdateOptions.KeyFields: deberia tenes los campos que hacen parte de la llave primaria.

2. Verificar, en un FDQuery o FDTable la propiedad UpdateOptions.updateMode: Si la tabla tiene llave primaria esta propiedad debería establecerse en upWhereKeyOnly .

3. En el inspector de objetos, por cada campo de la llave primaria, verificar las propiedades ProviderFlags.pfInupdate, ProviderFlags.pfInWhere.

Generalmente FireDac configura "el solito", sin que nosotros tengamos que hacer nada, todos estos atributos correctamente en tiempo de diseño con solo escribir la consulta SQL; pero en ocasiones FireDac requiere de nuestra ayuda para hacer su trabajo, ejemplo: Cuando la consulta tiene joins, Cuando la consulta se hace sobre una vista, cuando la consulta se hace sobre un procedimiento almacenado, cuando la tabla no tiene definda una primary key sino indices únicos, Cuando el DBA restringe el acceso a metadatos y FireDac no puede tener acceso a información sobre la definición de la tabla, etc.

Espero que lo anterior te sirva de orientación para solucionar tu problema.

JoAnCa 29-09-2018 18:11:57

Cita:

Empezado por Casimiro Notevi (Mensaje 528695)
¿Y qué es fdtPrenomGTDir?

fdtPrenomGTDir y fdtPrenomGTCons son controles TFDTable, tablas de FireDAC

fdtPrenomGTDir se basa en una vista de mysql, y la filtro por la categoria de la direccion y fdtPrenomGTCons es lo mismo, pero filtrandola por la categoria de los consultores

La vista de mysql es como ya dije, la tabla prenomina y trabajadores unidas por su relacion uno a muchos

JoAnCa 29-09-2018 18:24:33

Cita:

Empezado por orodriguezca (Mensaje 528697)
En mi experiencia, las veces que he tenido ese error, es porque FireDac no tiene la información suficiente o correcta para actualizar la información de los registros de la base de datos, esto es, FireDac trata de hacer un update sobre un registro pero el registro, según FirecDac, ya no existe. Cosas para revisar en estos casos:

1. Si la tabla tiene llave primaría verificar si en un FDQuery o FDTable está correctamente asignada la propiedad UpdateOptions.KeyFields: deberia tenes los campos que hacen parte de la llave primaria.

2. Verificar, en un FDQuery o FDTable la propiedad UpdateOptions.updateMode: Si la tabla tiene llave primaria esta propiedad debería establecerse en upWhereKeyOnly .

3. En el inspector de objetos, por cada campo de la llave primaria, verificar las propiedades ProviderFlags.pfInupdate, ProviderFlags.pfInWhere.

Generalmente FireDac configura "el solito", sin que nosotros tengamos que hacer nada, todos estos atributos correctamente en tiempo de diseño con solo escribir la consulta SQL; pero en ocasiones FireDac requiere de nuestra ayuda para hacer su trabajo, ejemplo: Cuando la consulta tiene joins, Cuando la consulta se hace sobre una vista, cuando la consulta se hace sobre un procedimiento almacenado, cuando la tabla no tiene definda una primary key sino indices únicos, Cuando el DBA restringe el acceso a metadatos y FireDac no puede tener acceso a información sobre la definición de la tabla, etc.

Espero que lo anterior te sirva de orientación para solucionar tu problema.

Muy buena su explicación, veo que en los problemas de FireDAC esta mi caso, pues uso una vista que tiene join

Revisaré todo lo que me explicas y despues te comento como me fue

JoAnCa 29-09-2018 19:10:47

Resuelto
 
Ok, parece que ya se soluciono el problema
Lo que hice fue:
- Inclui en la vista las 2 llaves de la relacion (pues tenia solo la del lado muchos)
- Asigne la llave en la propiedad UpdateOptions.KeyFields

Probé calculando varias veces seguidas en cada área, y no ha dado mas el error ^\||/

Muchas gracias por la ayuda

Casimiro Notevi 29-09-2018 19:20:12

^\||/^\||/^\||/

orodriguezca 01-10-2018 01:10:35

:)^\||/^\||/^\||/


La franja horaria es GMT +2. Ahora son las 20:24:59.

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