Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 03-07-2016
jose001 jose001 is offline
Miembro
NULL
 
Registrado: jul 2016
Posts: 13
Poder: 0
jose001 Va por buen camino
Prolema con guardar datos usando un tStringGrid

Hola buenas tardes estoy trabajando con una aplicacion de venta usando mysql y zeos para lo cual cargo en un TstringGrid los datos como (idproducto,nombre,cantidad,precio,subtotal) luego al apretar el boton aceptar se guarda el idventa,fecha,idcliente y el total que seria la suma de todos los sub totales. El tema es el siguiente cuando guardo los datos en la base se cargan 2 filas una con los valores de la venta realizada y otra fila vacia con todos los campos null
por ejemplo en la tabla venta
Código SQL [-]
idventa
total
idcliente
fecha

se carga lo siguiente para dejarlo mas claro
idventa:1
idcliente:null
total:null
fecha:null
y en otra fila se carga por fin los datos guardados
idventa:2
idcliente:2
total:20
fecha:2016-07-02





Dejo el codigo del boton aceptar


Código Delphi [-]
procedure TfVentas.bAceptarClick(Sender: TObject);
var
i:integer;
begin

 try
  fmodulo.conexion.StartTransaction;
    with fmodulo,self do
     fmodulo.qVentas.Active:=true;
     fmodulo.qVentas.Insert;
     fmodulo.qVentas['idcliente']  := idcliente;
     fmodulo.qFecha.Open;
     fmodulo.qVentas['fechavent']  := fmodulo.qFecha['fecha'];
     fmodulo.qVentas['horavent']:= fmodulo.qFecha['hora'];
     fmodulo.qVentas['totalventa']:= eTotal.text;
     fmodulo.qFecha.Close;
     fmodulo.qVentas.Post;
     with fmodulo,self,sgDetalle do
     begin
       fmodulo.qdetalle.Active:=true;
       fmodulo.qProductos.Active:=true;
       for i := 1 to rowcount - 2 do
         begin
           fmodulo.qdetalle.Insert;
           fmodulo.qdetalle['idventa']:= fmodulo.qVentas['idventa'];
           fmodulo.qdetalle['idproducto']:= strtoint(sgDetalle.Cells[0,i]);
           fmodulo.qdetalle['precio_venta']:=  strtofloat(sgDetalle.Cells[2,i]);
           fmodulo.qdetalle['cantidad_venta']:= strtofloat(sgDetalle.Cells[3,i]);
           fmodulo.qdetalle.Post;

          if fmodulo.qProductos.Locate('idproducto',strtoint(sgDetalle.Cells[3,i],[]))= True then
           begin
            fmodulo.qProductos.Edit;
             fmodulo.qProductos['cantidadpr']:= fmodulo.qproductos['cantidadpro']-StrToInt(cells[2,i]);
              fmodulo.qProductos.Post;
           end;
         end;
     end;
finally
  fmodulo.conexion.Commit;
end;


Del boton que utilizo para seleccionar los productos

Código Delphi [-]
procedure TfListadosProductos.bSeleccionarClick(Sender: TObject);
begin
with fventas,fventas.sgDetalle,fmodulo do
fventas.sgDetalle.Cells[0,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['idproducto'];
fventas.sgDetalle.Cells[1,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['nombrepr'];
fventas.sgDetalle.Cells[2,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['precio_unit'];
fventas.sgDetalle.Cells[3,fventas.sgDetalle.RowCount-1]:= eCantidad.Text ;
subtotal:=  fmodulo.qProductos['precio_unit']*StrToInt(self.eCantidad.Text)  ;
fventas.sgDetalle.Cells[4,fventas.sgDetalle.RowCount-1]:= FloattoStr(subtotal);
total:=total+subtotal;
fventas.eTotal.Text:= floattostr(total);
fventas.sgDetalle.RowCount:= fventas.sgDetalle.RowCount+1;
end;

espero que puedan ayudarme con este problema muchas gracias
Responder Con Cita
  #2  
Antiguo 03-07-2016
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
No das informacion suficiente. No sabemos que son todos los componentes de acceso a datos que estas usando: qFecha, qVentas, etc. Sobre estos componenes invocas al metodo Open y no sabemos si estaras ejecutando un SQL

Ademas, tu codigo tiene varios problemas. En ningun lado chequeas por errores; el resumen es:

Código Delphi [-]
  Conexion.StartTransaction;
  try
    codigo 
  finally
    Conexion.Commit;
  end;

Eso es un problema grave porque si se graba algun dato (ocurre un .Post) y luego mas adelante se produce un error (sobre todo con tanta conversion de string a otro tipo), se ejecuta el bloque finally, es decir, se ejecuta el Commit y te queda la informacion a medias (inconsistente)

Te sugiero que lo hagas de esta manera:

Código Delphi [-]
  Conexion.StartTransaction;
  try
    codigo 

    fin del codigo
    Connection.Commit;
  except
    Conexion.Rollback;
  end;


Por otra parte, el codigo es muy complicado de leer: with entre 2 o 3 objetos, luego otro with anidado. Es imposible saber que objeto recibe los mensajes

Ademas, el modo que usas para asignar los valores a cada campo es peligroso, ya que estas asignando a un Variant

Código Delphi [-]
  fmodulo.qVentas['idcliente']

Cuando en realidad el Variant se deberia usar si "no se el tipo del dato", pero aca los conoces perfectamente por lo que va a ser mas seguro, rapido y facil de entender si lo cambias por esto:

Código Delphi [-]
  fmodulo.qVentas.FieldByName('idcliente').AsInteger := VariableInteger;
 
  ...
  fmodulo.qVentas.FieldByName('algun_campo').AsString := VariableString;
  fmodulo.qVentas.FieldByName('algun_campo').AsFloat := VariableSingle/Double/Extended;
  fmodulo.qVentas.FieldByName('algun_campo').AsCurrency := VariableCurrency;
  
  etc
  ...
Responder Con Cita
  #3  
Antiguo 03-07-2016
jose001 jose001 is offline
Miembro
NULL
 
Registrado: jul 2016
Posts: 13
Poder: 0
jose001 Va por buen camino
Gracias

Cita:
Empezado por AgustinOrtu Ver Mensaje
No das informacion suficiente. No sabemos que son todos los componentes de acceso a datos que estas usando: qFecha, qVentas, etc. Sobre estos componenes invocas al metodo Open y no sabemos si estaras ejecutando un SQL

Ademas, tu codigo tiene varios problemas. En ningun lado chequeas por errores; el resumen es:

Código Delphi [-]
  Conexion.StartTransaction;
  try
    codigo 
  finally
    Conexion.Commit;
  end;

Eso es un problema grave porque si se graba algun dato (ocurre un .Post) y luego mas adelante se produce un error (sobre todo con tanta conversion de string a otro tipo), se ejecuta el bloque finally, es decir, se ejecuta el Commit y te queda la informacion a medias (inconsistente)

Te sugiero que lo hagas de esta manera:

Código Delphi [-]
  Conexion.StartTransaction;
  try
    codigo 

    fin del codigo
    Connection.Commit;
  except
    Conexion.Rollback;
  end;


Por otra parte, el codigo es muy complicado de leer: with entre 2 o 3 objetos, luego otro with anidado. Es imposible saber que objeto recibe los mensajes

Ademas, el modo que usas para asignar los valores a cada campo es peligroso, ya que estas asignando a un Variant

Código Delphi [-]
  fmodulo.qVentas['idcliente']

Cuando en realidad el Variant se deberia usar si "no se el tipo del dato", pero aca los conoces perfectamente por lo que va a ser mas seguro, rapido y facil de entender si lo cambias por esto:

Código Delphi [-]
  fmodulo.qVentas.FieldByName('idcliente').AsInteger := VariableInteger;
 
  ...
  fmodulo.qVentas.FieldByName('algun_campo').AsString := VariableString;
  fmodulo.qVentas.FieldByName('algun_campo').AsFloat := VariableSingle/Double/Extended;
  fmodulo.qVentas.FieldByName('algun_campo').AsCurrency := VariableCurrency;
  
  etc
  ...
Hola disculpa no me exprese bien y me faltaron cosas por decir utilizo componentes Tquery de zeos en los cuales tengo uno de detalle y otro tquery de ventas en cada uno tengo una sentencia sql que es la siguiente
Código SQL [-]
 Query venta
SELECT 
  `venta`.`idventa`,
  `venta`.`totalventa`,
  `venta`.`estadoventa`,
  `venta`.`idcliente`,
  `venta`.`fechavent`,
  `venta`.`horavent`
 
FROM
  `venta`

Código SQL [-]
 Query detalle venta
SELECT 
  `detalle_venta`.`idventa`,
  `detalle_venta`.`idproducto`,
  `detalle_venta`.`cantidad_venta`,
  `detalle_venta`.`precio_venta`,
  `detalle_venta`.`estado_detalleventa`
FROM
  `detalle_venta`

// en esta sentencia amigo me tira el siguiente error "Invalid operation in AutoCommit mode"
Connection.Commit;
except
Conexion.Rollback;
end;

Aun soy muy nuevo en esto soy estudiante, y ese es el codigo que me dijieron que utilize para trabajar con el TstringGrid me dijieron que debia hacer esas conversiones para guardar los datos.Por ejemplo si deberia guardar

Código Delphi [-]
fmodulo.qdetalle['idproducto']:= strtoint(sgDetalle.Cells[0,i]);
esta linea quedaria algo parecido a esto ?
Código Delphi [-]
fmodulo.qdetalle.FieldByName('idproducto').AsInteger:= strtoint(sgDetalle.Cells[0,i]);
gracias amigo por la respuesta y la ayuda
Responder Con Cita
  #4  
Antiguo 03-07-2016
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Con respecto al AutoCommit no puedo ser muy preciso, porque nunca he usado Zeos. Pero todo apunta a que hay una propiedad AutoCommit que por defecto viene a True, y habria que pasarla a False. Yo me he acostumbrado a realizar manejo explicito de transacciones, es decir, decidir cuando inician y como finalizan

Para la segunda consulta si, me parece mucho mas adecuado que uses la forma .AsInteger/.AsString

Otra sugerencia es eliminar los with de tu codigo

Por ejemplo, cuidado con este metodo que tienes en el boton de seleccionar:

Código Delphi [-]
procedure TfListadosProductos.bSeleccionarClick(Sender: TObject);
begin
with fventas,fventas.sgDetalle,fmodulo do
fventas.sgDetalle.Cells[0,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['idproducto'];
fventas.sgDetalle.Cells[1,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['nombrepr'];
fventas.sgDetalle.Cells[2,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['precio_unit'];
fventas.sgDetalle.Cells[3,fventas.sgDetalle.RowCount-1]:= eCantidad.Text ;
subtotal:=  fmodulo.qProductos['precio_unit']*StrToInt(self.eCantidad.Text)  ;
fventas.sgDetalle.Cells[4,fventas.sgDetalle.RowCount-1]:= FloattoStr(subtotal);
total:=total+subtotal;
fventas.eTotal.Text:= floattostr(total);
fventas.sgDetalle.RowCount:= fventas.sgDetalle.RowCount+1;
end;

No entiendo muy bien el porque usas el with en ese caso. Pero vamos por partes

Primero que el with al no estar delimitado por un bloque begin-end, solamente "afecta" a la siguiente instruccion inmediata. Es decir, en tu caso (coloreo con negro la linea que es "afectada" por el with, y le agrego un sangrado para que quede bien claro)

Código Delphi [-]
procedure TfListadosProductos.bSeleccionarClick(Sender: TObject);
begin
  with fventas,fventas.sgDetalle,fmodulo do
    fventas.sgDetalle.Cells[0,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['idproducto'];

  fventas.sgDetalle.Cells[1,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['nombrepr'];
  fventas.sgDetalle.Cells[2,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['precio_unit'];
  fventas.sgDetalle.Cells[3,fventas.sgDetalle.RowCount-1]:= eCantidad.Text ;
  subtotal:=  fmodulo.qProductos['precio_unit']*StrToInt(self.eCantidad.Text)  ;
  fventas.sgDetalle.Cells[4,fventas.sgDetalle.RowCount-1]:= FloattoStr(subtotal);
  total:=total+subtotal;
  fventas.eTotal.Text:= floattostr(total);
  fventas.sgDetalle.RowCount:= fventas.sgDetalle.RowCount+1;
end;

Fijate como el resto de las instrucciones no son alcanzadas por tu with

Por otra parte, concentremonos en lo que quiere transmitir tu codigo. Mas alla de que no se aconseja el uso del with por los varios problemas que puede tener (sobre todo la ambiguedad), uno usa un with para "ahorrarse" el trabajo de no volver a escribir a que objeto le quiere mandar un mensaje

Pero aun asi, usas el with sobre un objeto, y en el cuerpo del codigo sigues referenciando el objeto en cuestion. Osea, el with esta totalmente de mas!

Código Delphi [-]
procedure TfListadosProductos.bSeleccionarClick(Sender: TObject);
begin
  with fventas,fventas.sgDetalle,fmodulo do
    fventas.sgDetalle.Cells[0,fventas.sgDetalle.RowCount-1]:= fmodulo.qProductos['idproducto'];

fventas no lo usas nunca
En el with, colocas un fventas.sgDetalle, pero en el codigo, en vez de usar "la forma abreviada" y obviar el fventas.sgDetalle, lo vuelves a escribir

El mismo caso es para fmodulo

Ese mismo codigo se puede escribir asi, resultando mucho mas claro de leer:

Código Delphi [-]
procedure TfListadosProductos.bSeleccionarClick(Sender: TObject);
begin
    fventas.sgDetalle.Cells[0, fventas.sgDetalle.RowCount - 1] := fmodulo.qProductos['idproducto'];
   // resto del codigo

Este mismo problema lo tenes en el codigo de grabado:

Código Delphi [-]
    with fmodulo,self do
     fmodulo.qVentas.Active:=true;

   // mas codigo

Sin embargo, mas abajo en el mismo metodo usas un begin-end para un with

Código Delphi [-]
     with fmodulo,self,sgDetalle do
     begin
       // codigo
     end;

Pregunta: Por que usas el with? Para que sirve? Quien te dijo que uses with? Usaste algun codigo de ejemplo para guiarte?. En definitiva, te recomiendo no usarlo (mejor aprenderlo desde novato asi no te queda como vicio)

Luego te recomiendo que "embellezcas" tu codigo:

1- Utiliza la sangria de forma inteligente: Respeta los distintos niveles de anidamiento de los bloques (facilita la lectura). Ejemplo:

Código Delphi [-]
  if AlgunaCondicion then
  begin
    instruccion1;
    instruccion2;
    if OtraCondicion then
    begin
      instruccion2.1;
      instruccion2.2
   end;
  end;

Eso es mucho mas facil de leer que esto, o similares, donde no se respeta un orden:

Código Delphi [-]
  if AlgunaCondicion then
  begin
  instruccion1;
      instruccion2;
  if OtraCondicion then
  begin
      instruccion2.1;
  instruccion2.2
  end;
  end;

2 - Si bien en Delphi no se distinguen mayusculas de minusculas (yo lo veo como un gran error de diseño), el escribir todo en mayusculas o todo en minusculas hace mas dificil leer el codigo. Piensa en alguien que da un discurso y usa siempre el mismo tono de voz, sin ningun tipo de pausa. Esto es lo mismo.

Código Delphi [-]
  fmodulo.qdetalle.fieldbyname('idproducto').asinteger:= strtoint(sgdetalle.cells[0,i]);  

  FModulo.qDetalle.FieldByName('IdProducto').AsInteger:= StrToInt(sgDetalle.Cells[0, I]);

Esto implica tambien respetar los nombres de las cosas que ya vienen implementadas. Por ejemplo, nadie te obliga a seguir la notacion PascalCase para escribir tu propio codigo (es cierto que estoy tocando un tema muy personal) pero si me parece correcto que lo que ya esta escrito de una manera, respetarlo: lo mas probable es que el resto de los programadores escribamos StrToInt y no strtoint o strToInt. De este modo tu codigo queda idiomatico y es mas facil de leer

3 - No gastas mas memoria por ponerle nombres largos a las variables . Es preferible un nombre de variable largo a uno corto. Es mas importante que se entienda bien para que sirve. No se en donde se aprendio que los nombres de las variables son siempre: tot, sum, i, temp, x, y, z, temp_x... ponle el nombre de lo que realmente significan!

4 - Aprende a depurar un programa. No importa si eres novato, intermedio, experto o entusiasta. Programar sin saber depurar es como pretender correr sin saber caminar. Una cosa lleva a la otra.

El depurador de Delphi es increible, podes seguir paso a paso como se ejecuta tu codigo, detenerte en el momento que quieras, ver el valor de todas las variables del programa, ver que es lo que exactamente hace, seguir el flujo de ejecucion, incluso el depurador te permite modificar los valores de las variables para "ver que pasa si aca en lugar de 100 vale 101".
Incluso podes monitorear los valores de las variables para ver como se van actualizando

Hay muchos hilos sobre como depurar en el foro, con una busqueda encontraras muchos resultados
Responder Con Cita
  #5  
Antiguo 04-07-2016
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.038
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Buenísima y didáctica la respuesta
Cita:
Empezado por AgustinOrtu Ver Mensaje
2 - Si bien en Delphi no se distinguen mayusculas de minusculas (yo lo veo como un gran error de diseño), el escribir todo en mayusculas o todo en minusculas hace mas dificil leer el codigo.
Responder Con Cita
Respuesta



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
Guardar usando store procedure ronimaxh SQL 5 02-12-2011 23:07:24
No muestra datos en TStringGrid Ziara C++ Builder 2 20-01-2009 17:23:25
Guardar Solo Hora usando DateTimePicker georgejg Conexión con bases de datos 6 23-03-2008 10:12:29
Introducir datos en un TStringGrid Bauhaus1975 Varios 3 11-05-2006 18:29:23
Prolema con Register en Interbase esocrates Firebird e Interbase 6 10-04-2004 22:31:47


La franja horaria es GMT +2. Ahora son las 00:21:54.


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
Copyright 1996-2007 Club Delphi